SELF-JOIN discarding true CROSS JOIN rows - sql

I have the following query;
What I get is tickets information. I use self-join to obtain the requester and the assignee in the same row:
SELECT z.id AS TICKET, z.name AS Subject, reqs.name AS Requester, techs.name AS Assignee,
e.name AS Entity,DATE_FORMAT(tt.date,'%y%-%m%-%d') AS DATE,
DATE_FORMAT(tt.date,'%T') AS HOUR,
CASE WHEN z.priority = 6 THEN 'Mayor' WHEN z.priority = 5 THEN 'Muy urgente' WHEN z.priority = 4 THEN 'Urgente'WHEN z.priority = 3 THEN 'Mediana' WHEN z.priority = 2 THEN 'Baja' WHEN z.priority =1 THEN 'Muy baja' END AS Priority,
c.name AS Category, i.name AS Department
FROM glpi_tickets_users tureq
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id
JOIN glpi_users AS reqs ON tureq.users_id = reqs.id
JOIN glpi_users AS techs ON tutech.users_id = techs.id
JOIN glpi_tickets z ON z.id = tureq.tickets_id
LEFT OUTER JOIN glpi_tickettasks tt ON z.id = tt.tickets_id
LEFT JOIN glpi_itilcategories i ON z.itilcategories_id = i.id
LEFT JOIN glpi_usercategories c ON c.id = reqs.usercategories_id
INNER JOIN glpi_entities e ON z.entities_id = e.id
WHERE (tureq.id < tutech.id AND tureq.type < tutech.type) OR
(tureq.id < tutech.id AND tureq.users_id = tutech.users_id) OR
(tureq.id = tutech.id AND tureq.users_id = tutech.users_id)
The problem is that I get something like that:
1 Report jdoe jdoe Development 16-06-07 11:56:17 Mediana Software Mkt
1 Report jdoe fwilson Development 16-06-07 11:56:17 Mediana Software MKt
1 Report fwilson fwilson Development 16-06-07 11:56:17 Mediana Software Mkt
2 Task11 gwilliams gwilliams Ops 16-06-08 12:00:00 ALTA Hardware Def
3 Task12 gwilliams gwilliams Ops 16-06-08 12:01:00 ALTA Hardware Def
I don't want first and third row because is a CROSS JOIN result. Second row is OK, because jdoe is a requester and fwilson an assignee.
The problem is that sometimes requester and assignee are the same, eg: he creates a ticket for a task that himself will do. For example, 4th and 5th rows are OK.
So, how should I do to make a difference for those distinct cases, i.e.: I need to include:
tureq.id = tech.id AND req.users_id = tech.users.id
BUT NOT IF ALREADY EXISTS
tureq.id = tech.id AND req.users_id <> tech.users_id
Update
The main problem is that a user can assign to himself a ticket:
SELECT * from glpi_tickets_users WHERE type = 2 GROUP BY tickets_id HAVING COUNT(users_id)<2 limit 3;
+----+------------+----------+------+------------------+-------------------+
| id | tickets_id | users_id | type | use_notification | alternative_email |
+----+------------+----------+------+------------------+-------------------+
| 1 | 2 | 12 | 2 | 1 | NULL |
| 3 | 6 | 13 | 2 | 1 | NULL |
| 7 | 8 | 14 | 2 | 1 | NULL |
+----+------------+----------+------+------------------+-------------------+
Update 2:
It was a human mistake. The problem was really not about self-assigned tickets. Rather it was either that some tickets had not Requester or had Requester but still had not any resolver assigned.
I've found

As there are always the two types per ticket you are interested in, you can simply select the according records, so as to get requester and assignee per ticket.
select
t.id as ticket,
t.name as subject,
requester.name as requester,
assignee.name as assignee,
e.name as entity,
date_format(tt.date,'%y%-%m%-%d') as date,
date_format(tt.date,'%T') as hour,
case t.priority
when 6 then 'Mayor'
when 5 then 'Muy urgente'
when 4 then 'Urgente'
when 3 then 'Mediana'
when 2 then 'Baja'
when 1 then 'Muy baja'
end as priority,
uc.name as category,
ic.name as department
from glpi_tickets t
join glpi_entities e on e.id = t.entities_id
join
(
select tu.tickets_id, u.name, u.usercategories_id
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 1
) requester on requester.tickets_id = t.id
join
(
select tu.tickets_id, u.name
from glpi_tickets_users tu
join glpi_users u on u.id = users_id
where tu.type = 2
) assignee on assignee.tickets_id = t.id
left join glpi_itilcategories ic on ic.id = t.itilcategories_id
left join glpi_usercategories uc on uc.id = requester.usercategories_id;
left outer join glpi_tickettasks tt on tt.tickets_id = t.id
The only thing I wonder is: There can be several ticket tasks per ticket. So what do you want to do then? Have one line per ticket task in your results? This is what the query does. Only, it looks queer that your result rows don't contain any information on the tasks except for the dates, so you may have many, many lines with the same data, only with different dates. So maybe, you'd rather want the first or last date per ticket. To get the last date per ticket, you'd replace the last line in the query with:
left outer join
(
select tickets_id, max(date) as date
from glpi_tickettasks
group by tickets_id
) tt on tt.tickets_id = t.id
And you probably want to add an ORDER BY clause.

you need to add more qualifiers to your joins for example
JOIN glpi_tickets_users tutech ON tureq.tickets_id = tutech.tickets_id and tutech.type = 2

Related

How to calculate SQL percentages based on join of two tables, with only one row showing for each assignment

How do I calculate the percentages of those who successfully subscribed? If someone with uID (1 for example) has Not Yet, but then Sub then this is a 100% conversion.
I want to calculate the percentages of each assignmentID group. There can be multiple users in each assignmentID group.
My Query:
SELECT assignmentID,
(SELECT count(assignment)
FROM group JOIN Subscribed ON group.uID = Subscribed.uID
WHERE assignment ='test' and status ='Sub') /
(SELECT count(assignment) FROM group JOIN Subscribed ON group.uID = Subscribed.uID) testconversion,
(SELECT count(assignment)
FROM group JOIN Subscribed ON group.uID = Subscribed.uID
WHERE assignment ='control' and status ='Sub') /
(SELECT count(assignment) FROM group JOIN Subscribed ON group.uID = Subscribed.uID) controlconversion
FROM group JOIN Subscribed ON group.uID = Subscribed.uID
GROUP BY assignmentID
Subscribed
uID Status
1 Not Yet
1 Sub
3 Not Yet
4 Not Yet
5 Sub
Group
uID Assignment AssignmentID
1 test 1
2 test 2
1 control 1
4 test 2
5 test 1
Expected Output:
AssignmentID testconversion controlconversion
1 100% 0%
2 50% null
This looks like a join and aggregation:
select g.assignmentid,
(countif(g.assigned = 'test' and s.status = 'sub') /
nullif(countif(g.assigned = 'test'), 0)
) as test_conversion,
(countif(g.assigned = 'control' and s.status = 'sub') /
nullif(countif(g.assigned = 'control'), 0)
) as control_conversion,
from subscribers s join
grouped g
using (uid)
group by g.assignmentid

Nesting Queries to get multiple column results

Have two queries , one collects moves in based on property and unit type the other would collect based on Move Outs for the same data. when ran separately they yield the correct information (move outs are 6 and move ins are 11) Have tried nesting in select and from statements but not getting what i need. When nested within the select am getting the correct move outs per unit type, but each line for move ins is total move ins. I recall that the nesting here would only return one value but know there is a way to return the value for each row. Any assistance is appreciated.
SELECT
p.scode as PropNumber,
p.saddr1 propname,
ut.scode as UnitType,
COUNT(t.hmyperson) as Moveouts,
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t
JOIN unit u ON t.hunit = u.hmy
JOIN property p ON p.hmy = u.hproperty
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
t.dtmovein >= getdate() - 14
AND p.scode IN ('gsaff')
) mi
FROM
Property p
JOIN unit u ON u.hproperty = p.hmy
JOIN tenant t ON t.hunit = u.hmy
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
p.scode IN ('gsaff')
AND t.DTMOVEOUT >= getdate()- 14
GROUP BY
ut.scode,
p.scode,
p.saddr1
With this data is coming out like :
PropNumber Propname UnitType MoveOuts MoveIns
1 x tc2 1 11
1 x tc3 2 11
1 x tc4 1 11
1 x tc5 1 11
1 x tc6 1 11 <pre>
Move in column should display as
2
5
1
0
3
You need to correlate the subquery according to the record being processed in the outer query. This also requires that you use different table aliases in the subquery than in the outer query.
It is hard to tell without seeing sample data, however I would expect that you need to correlate with all non-aggregated columns in the outer query.
Try changing :
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t
JOIN unit u ON t.hunit = u.hmy
JOIN property p ON p.hmy = u.hproperty
JOIN unittype ut ON ut.hmy = u.HUNITTYPE
WHERE
t.dtmovein >= getdate() - 14
AND p.scode IN ('gsaff')
) mi
To :
(
SELECT COUNT(t.hmyperson) as MoveIns
FROM
tenant t1
JOIN unit u1 ON t1.hunit = u1.hmy
JOIN property p1 ON p1.hmy = u1.hproperty
JOIN unittype ut1 ON ut1.hmy = u1.HUNITTYPE
WHERE
t1.dtmovein >= getdate() - 14
AND p1.scode IN ('gsaff')
AND p1.scode = p.scode
AND p1.saddr1 = p.saddr1
AND ut1.scode = ut.scode
) mi

Avoid third table multiplying results

I have three tables.
Defect: Main table used to store defects found.
FollowUp: Table that stores followups to a specific Defect.
Defect_Attach: Related table used all photo attachments for Defects and FollowUps.
How can I get dates for all photo attachments?
Some of these photos were taken for a defect, then at a later date, more photos were related to the defect during a followup.
The results I'm trying to get would look something like this:
or
So far my query looks like this:
SELECT d.GUID
,p.ATTACHMENTID
,p.REL_OBJECTID
,p.CONTENT_TYPE
,p.ATT_NAME
,p.DATA_SIZE
,d.DateObserved as 'Defect Date'
--,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
--LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
But as soon as I try joining my third table (FOLLOWUP), my results multiply.
UPDATE:
Results:
SELECT p.ATT_NAME
,d.DateObserved as 'Defect Date'
--,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
--LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
Joining THIRD Table:
SELECT p.ATT_NAME
,d.DateObserved as 'Defect Date'
,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
SELECT
d.DateObserved AS defect_date,
p.ATT_NAME AS photo_name,
f.DateObserved AS follow_up_date
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY REL_OBJECTID
ORDER BY ATT_NAME) AS ordinal
FROM
ECIMUSR.DEFECT__ATTACH
)
p
FULL OUTER JOIN
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY DefectGUID
ORDER BY DateObserved) AS ordinal
FROM
ECIMUSR.FOLLOWUP
)
f
ON f.DefectGUID = p.REL_OBJECTID
AND f.ordinal = p.ordinal
RIGHT JOIN
ECIMUSR.DEFECT d
ON d.ObjectID = COALESCE(f.DefectGUID, p.REL_OBJECTID)
Would give something like...
defect_date | photo_name | follow_up_date
-------------+-----------------------------+----------------
2014-12-19 | photo1.jpg | 2015-01-16
2014-12-19 | PhotoFollowUp1_20150117.jpg | 2015-03-19
2014-12-19 | PhotoFollowUp1_20150324.jpg | 2015-04-17
2014-12-19 | PhotoFollowUp1_20150417.jpg | NULL
2014-12-19 | PhotoFollowUp2_20150324.jpg | NULL
The photo names and the follow up dates have nothing to do with each others. they're just in alphabetical order with gaps if one list is longer than the other.

Combine results of two different records in one

I have an SQL data stored in a single table but with different type and I want to combine the result in one liner show in the example below. Anyone can give suggestion to this SQL query?
My SQL query to get this results:
SELECT NumValue, Label, Type
FROM (CustomPollerStatusTable
INNER JOIN CustomPollers ON (CustomPollerStatusTable.PollerID =
CustomPollers.CustomPollerID))
INNER JOIN Nodes ON (CustomPollerStatusTable.NodeID = Nodes.NodeID)
WHERE ((Nodes.Caption = 'fqdn') AND
(CustomPollers.Type = 'Student Info') AND
(CustomPollerStatusTable.NumValue > 89) AND
(NOT (CustomPollerStatusTable.Label LIKE '%.snapshot%')) AND
(NOT (CustomPollerStatusTable.Label LIKE '%aggr%')) AND
(NOT (CustomPollerStatusTable.Label = '/vol/scratch/'))
)
====================================
NumValue | Label | Type
====================================
90 | Student 1 | Student Info
10 | Student 1 | Student Class
====================================
The results that I would like to achieve:
==========================================================================
NumValue.Info | NumValue.Class | Label | Type.Info | Type.Class
==========================================================================
90 | 10 | Student 1 | Student Info | Student Class
==========================================================================
This should do it. Slightly different from nrathaus' answer. Obviously you can use as to change the column names to whatever you want.
select
s1.NumValue,
s2.NumValue,
s1.Label,
s1.Type,
s2.Type
from Student s1 inner join Student s2
on s1.Label = s2.Label
where s1.Type like '%Info'
and s2.Type like '%Class'
EDIT: Now that you have posted your select statement I think this might not work. Can you post the table structure?
EDIT2: This might work.
INSERT INTO TempTable(
NumValInfo,
Label,
TypeInfo)
SELECT
c.NumValue,
c.Label,
p.Type
FROM (CustomPollerStatusTable c INNER JOIN CustomPollers p
ON (c.PollerID = p.CustomPollerID))
INNER JOIN Nodes n
ON (c.NodeID = n.NodeID)
WHERE n.Caption = 'fqdn'
AND p.Type = 'Student Info'
AND c.NumValue > 89
AND NOT (c.Label LIKE '%.snapshot%')
AND NOT (c.Label LIKE '%aggr%')
AND NOT (c.Label = '/vol/scratch/')
AND p.Type like '%Info'
UPDATE TempTable set
NumValClass = c.NumValue,
TypeClass = p.Type
FROM (CustomPollerStatusTable c INNER JOIN CustomPollers p
ON (c.PollerID = p.CustomPollerID))
INNER JOIN Nodes n
ON (c.NodeID = n.NodeID)
INNER JOIN TempTable t
ON t.Label = c.Label
WHERE n.Caption = 'fqdn'
AND p.Type = 'Student Info'
AND c.NumValue > 89
AND NOT (c.Label LIKE '%.snapshot%')
AND NOT (c.Label LIKE '%aggr%')
AND NOT (c.Label = '/vol/scratch/')
AND p.Type like '%Class'
SELECT * FROM TempTable
I think this will do:
SELECT tblInfo.NumValue AS `NumValue.Info`,
tblClass.NumValue AS `NumValue.Class`,
Table.Label AS Label,
tblInfo.Type AS `Type.Info`,
tblClass.Type AS `Type.Class`
FROM (Table)
LEFT JOIN Table AS tblInfo ON tblInfo.Label = Table.Label ON tblInfo.Type = 'Student Info'
LEFT JOIN Table AS tblClass ON tblClass.Label = Table.Label ON tblClass.Type = 'Student Class'
GROUP BY Table.Label

Count Unique Results in T-SQL

My query is:
SELECT DISTINCT IncidentStatus.IncidentStatusName, Incident.IncidentID AS Bob
FROM Incident
INNER JOIN IncidentMember
ON Incident.IncidentID = IncidentMember.IncidentId
INNER JOIN IncidentStatus
ON Incident.IncidentStatusID = IncidentStatus.IncidentStatusID
WHERE (IncidentMember.MemberId = 6)
And the result is:
IncidentStatusName Bob
---------------------------
Closed 9267
In Progress 9251
In Progress 9289
New 7893
Resolved 7750
Required Result is:
IncidentStatusName Bob
---------------------------
Closed 1
In Progress 2
New 1
Resolved 1
Help Requested.
SELECT IncidentStatus.IncidentStatusName, COUNT(Incident.IncidentID) AS Bob
FROM Incident
INNER JOIN IncidentMember ON Incident.IncidentID = IncidentMember.IncidentId
INNER JOIN IncidentStatus ON Incident.IncidentStatusID = IncidentStatus.IncidentStatusID
WHERE (IncidentMember.MemberId = 6)
GROUP BY IncidentStatus.IncidentStatusName
Or maybe you need COUNT(DISTINCT Incident.IncidentID) (depends on your table structure)
take your PK field, Incident.IncidentID, out of the select distinct clause