Single query has 359 results but cte with multi table left join has 396 results. Why? - sql

I am working with a query and 2 tables. This first query
SELECT * FROM B_WORKERACTIVITY
WHERE COURTCASENO IS NULL
AND WORKCOMMENT IS NOT NULL
gives 359 results. When I left join 2 tables to the query with a cte I get 396 results. I want to match the 2 tables to the query so that I only have 359 results. Below is what I've tried doing.
WITH cte AS (SELECT * FROM B_WORKERACTIVITY
WHERE COURTCASENO IS NULL
AND WORKCOMMENT IS NOT NULL )
SELECT
cte.*,
a.indssn,
i.firstname,
i.lastname
FROM cte LEFT JOIN TBLASSOC a
ON cte.REFERRALNO = a.REFERRALNO
LEFT JOIN TBLINDIVIDUALS i
ON i.INDSSN = a.INDSSN ;

Related

NOT EXISTS Vs. Left Outer Join

I am confused by the results that I am getting via the NOT EXISTS vs. LEFT OUTER JOIN with NULL.
Consider the below 2 queries which produce very different results. Please note that the fkMasterPersonID is NOT a foreign key to the right table (tblInternetMasterPerson)
Query 1
SELECT tl.pkLeadID, tl.fkMasterPersonID
FROM dbo.tblPhoneLead tl
WHERE NOT EXISTS (
SELECT MasterPersonID
FROM dbo.tblInternetMasterPerson
)
The above returns no results
Query 2
SELECT tl.pkLeadID, tl.fkMasterPersonID
FROM dbo.tblPhoneLead tl
LEFT JOIN dbo.tblInternetMasterPerson mp
ON tl.fkMasterPersonID = mp.MasterPersonID
WHERE tl.fkMasterPersonID IS null
The above returns 237 records where the fkMasterPersonID are all NULL.
What would be the correct way of determining through NOT EXISTS whether the fkMasterPersonID DOES NOT exist on the dbo.tblInternetMasterPerson? This table does have the column pkMasterPersonID but it is auto incremented and is not a foreign key to any other table.
You need to correlate the exists subquery to the outer query. Here is one way:
SELECT tl.pkLeadID, tl.fkMasterPersonID
FROM dbo.tblPhoneLead tl
WHERE NOT EXISTS (
SELECT 1
FROM dbo.tblInternetMasterPerson mp
WHERE mp.MasterPersonID = tl.fkMasterPersonID
);

Dynamically Table Name in Query based on Count

I would appreciate some suggestions on generating Dynamic Query based on count from my first Query.
For Example: In 757 BTID, We found Max Count of records so it should be our first table in the second Query.
Similarly 706 will be 2nd, 788-3rd, 715 will be 4th table in second query depending on Count.
This Will be different for each user as count is different
First Query:
SELECT btid, COUNT(*) FROM dbo.PERSON_EXPANDED
WHERE PID=31226 AND BTID IN (757,706,788,715)
GROUP BY btid
First Query Results:
757 15
706 14
788 12
715 11
Second Query:
SELECT *
FROM dbo.PERSON_EXPANDED E757
INNER JOIN dbo.PERSON_EXPANDED E706 ON E757.PID=E706.PID AND E706.BTID=706 AND E757.EffectiveDate BETWEEN E706.EffectiveDate AND E706.ExpirationDate
INNER JOIN dbo.PERSON_EXPANDED S788 ON E757.PID=S788.PID AND S788.BTID=788 AND E757.EffectiveDate BETWEEN S788.EffectiveDate AND S788.ExpirationDate
INNER JOIN dbo.PERSON_EXPANDED S715 ON E757.PID=S715.PID AND S715.BTID=715 AND E757.EffectiveDate BETWEEN S715.EffectiveDate AND S715.ExpirationDate
INNER JOIN dbo.EMPLOYEE E ON P.PID=E757.PID
WHERE E757.BTID=757
AND E.PID=31226
ORDER BY E757.EffectiveDate
Thank you...

Oracle9i-why this left join return empty result?

A LEFT OUTER JOIN is one of the JOIN operations that allow you to
specify a join clause. It preserves the unmatched rows from the first
(left) table, joining them with a NULL row in the shape of the second
(right) table.
Why the result of the last two queries is empty?
SELECT *
FROM PTB_YSQK;
-- 10 rows
SELECT *
FROM PTB_FP;
-- 10 rows
SELECT *
FROM PTB_YSQK
LEFT JOIN PTB_FP ON PTB_FP.YSID = PTB_YSQK.ID;
-- 10 rows
SELECT *
FROM PTB_YSQK
LEFT JOIN PTB_FP ON PTB_FP.ID IS NULL;
-- 0 rows
SELECT *
FROM PTB_YSQK
LEFT JOIN PTB_FP ON PTB_FP.ID = (
SELECT min(PTB_FP.ID)
FROM PTB_FP
WHERE PTB_FP.YSID = PTB_YSQK.ID
)
-- 0 rows
For detail of those tables, see https://gist.github.com/toaco/f3821f69ad86889abb43878ac2b4978d

Why are the result of COUNT double when I do two join? [duplicate]

This question already has answers here:
sql double count in join statement
(2 answers)
Closed 5 years ago.
I have this tables
device
id name groupId serviceId
791 Mamie Ortega 205 1832
group
id serviceId
205 1832
record
id date deviceId
792 2017-07-13 13:30:19.740360 784
793 2017-07-13 13:30:19.742799 784
alarms
id status deviceId
241 new 784
242 new 784
I'm running this query
SELECT device.id, device.name, COUNT(records.id) AS "last24HMessagesCount", COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "record" AS "records" ON "device"."id" = "records"."deviceId" AND "records"."date" > '2017-07-12 11:43:02.838 +00:00'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
Which give me this result
id name last24HMessagesCount activeAlarmsCount
791 Mamie Ortega 4 4
This result is wrong, I'm supposed to have 2 for last24HMessagesCount and activeAlarmsCount.
If I remove one of the count, last24HMessagesCount for example and execute
SELECT device.id, device.name, COUNT(alarms.id) AS "activeAlarmsCount"
FROM device
INNER JOIN "group" AS "group" ON "device"."groupId" = "group"."id" AND "group"."id" = '205'
LEFT OUTER JOIN "alarm" AS "alarms" ON "device"."id" = "alarms"."deviceId" AND "alarms"."status" = 'new'
WHERE "device"."serviceId" = 1832
GROUP BY device.id;
The result is correct
id name activeAlarmsCount
791 Mamie Ortega 2
I do not understand, why are the counts double?
This is very simple to answer. You have two record and two alarm. You join these and get four records, which you count.
You can workaround this problem by counting distinct IDs:
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
but I would not recommend this. Why do you join record and alarm anyway? They are not directly related. What you want to join is the number of record and the number of alarm. So aggregate before joining:
SELECT
device.id,
device.name,
records.cnt AS "last24HMessagesCount",
alarms.cnt AS "activeAlarmsCount"
FROM device
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM record
WHERE "date" > '2017-07-12 11:43:02.838 +00:00'
GROUP BY deviceId
) AS records ON device.id = records.deviceId
LEFT OUTER JOIN
(
SELECT deviceId, count(*) AS cnt
FROM alarm
WHERE status = 'new'
GROUP BY deviceId
) AS alarms ON device.id = alarms.deviceId
WHERE device.serviceId = 1832
AND device.groupId = 205;
(I've removed the unnecessary join to the "group" table.)
Your joins are producing a Cartesian product along two dimensions. The simplest solution is to use COUNT(DISTINCT):
SELECT device.id, device.name,
COUNT(DISTINCT records.id) AS "last24HMessagesCount",
COUNT(DISTINCT alarms.id) AS "activeAlarmsCount"
This works if the counts are not very large. An alternative solution is more scalable. That is to do the aggregation before the LEFT JOINs or using correlated subqueries (or lateral joins).

How do I put condition on a particular column after i joined two tables

I joined two tables to get two columns by using code:
SELECT rpt_Line_Shift_AvailableHrs.LineNumber
,rpt_Line_Shift_Prod.ShiftNumber
FROM rpt_Line_Shift_AvailableHrs
LEFT OUTER JOIN rpt_Line_Shift_Prod
ON rpt_Line_Shift_AvailableHrs.LineNumber=rpt_Line_Shift_Prod.LineNumber
the result I get is:
Line# , ShiftNumber
1 A
1 A
1 B
1 C
1 C
1 C
1 D
but I'm looking for a result like this
Line# , ShiftNumber
1 A
1 B
1 C
1 D
You can use distinct :
select distinct rpt_Line_Shift_AvailableHrs.LineNumber
, rpt_Line_Shift_Prod.ShiftNumber
from rpt_Line_Shift_AvailableHrs
left join rpt_Line_Shift_Prod on rpt_Line_Shift_AvailableHrs.LineNumber=rpt_Line_Shift_Prod.LineNumber
or the group by clause:
select rpt_Line_Shift_AvailableHrs.LineNumber
, rpt_Line_Shift_Prod.ShiftNumber
from rpt_Line_Shift_AvailableHrs
left join rpt_Line_Shift_Prod on rpt_Line_Shift_AvailableHrs.LineNumber=rpt_Line_Shift_Prod.LineNumber
group by rpt_Line_Shift_AvailableHrs.LineNumber
, rpt_Line_Shift_Prod.ShiftNumber
Try using DISTINCT to remove duplicates.
Select DISTINCT
rpt_Line_Shift_AvailableHrs.LineNumber,
rpt_Line_Shift_Prod.ShiftNumber
From
rpt_Line_Shift_AvailableHrs
left outer join rpt_Line_Shift_Prod
on rpt_Line_Shift_AvailableHrs.LineNumber=rpt_Line_Shift_Prod.LineNumber
If you want to make every row appear only once, you need to use SELECT DISTINCT with an otherwise unchanged query