| Author |
Topic |
|
jarrette
Starting Member
4 Posts |
Posted - 2008-12-03 : 14:59:50
|
I need to do the following...SELECT Description as DispositionName,(SELECT Count(*) FROM Calls c WHERE c.DispositionID = ??? AND DateLogged > '10/3/2008' AND DateLogged <= '12/3/2008') FROM Dispositions d where ??? is the dispositionID of the current row....Net Developer |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2008-12-03 : 15:16:06
|
SELECT Description as DispositionName,(SELECT Count(*) FROM Calls c WHERE c.DispositionID = d.DispositionID AND c.DateLogged > '10/3/2008' AND c.DateLogged <= '12/3/2008') FROM Dispositions d E 12°55'05.63"N 56°04'39.26" |
 |
|
|
jarrette
Starting Member
4 Posts |
Posted - 2008-12-03 : 15:18:07
|
| damnit, DUH, thanks Peso.Net Developer |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-03 : 16:34:10
|
something like this might work a bit faster, but the logic might need a bit of tweaking:SELECT d.Description as DispositionName, COUNT(c.DispositionID)FROM Dispositions dLEFT OUTER JOIN Calls c ON c.DispositionID = d.DispositionID AND c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description The advantage here is there is no subquery which can under certain circumstances cause a performance hit. SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2008-12-03 : 16:47:51
|
Take thisc.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'out of ON and put it into the WHERE clause.GreetingsWebfred No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-03 : 16:52:37
|
That would force an INNER JOIN on Calls, which would eliminate the 0 counts of Dispositions. SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2008-12-03 : 17:03:20
|
No this would shrink the "superset" and when i am thinking about it...the left join is completely useless because the OP would like to count only existing matches.quote: SELECT Count(*) FROM Calls c WHERE c.DispositionID = d.DispositionID AND c.DateLogged > '10/3/2008' AND c.DateLogged <= '12/3/2008'
The left join blows up the data that is to examine from the query processor. No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2008-12-03 : 17:17:52
|
The left join gives the correct results though:--SetupDECLARE @Dispositions TABLE (DispositionID INT, Description VARCHAR(100))INSERT @DispositionsSELECT 1, 'Dispo 1'UNION ALL SELECT 2, 'Dispo 2'UNION ALL SELECT 3, 'Dispo 3'UNION ALL SELECT 4, 'Dispo 4'DECLARE @Calls TABLE (DispositionID INT, DateLogged DATETIME)INSERT @CallsSELECT 1, '20081001'UNION ALL SELECT 1, '20081030'UNION ALL SELECT 1, '20081130'UNION ALL SELECT 3, '20081130'UNION ALL SELECT 3, '20081230'-- OrginalSELECT Description as DispositionName,(SELECT Count(*) FROM @Calls c WHERE c.DispositionID = d.DispositionID AND c.DateLogged > '10/3/2008' AND c.DateLogged <= '12/3/2008') FROM @Dispositions d -- Results--DispositionName (No column name)--Dispo 1 2--Dispo 2 0--Dispo 3 1--Dispo 4 0-- Query 1 - LEFT OUTER JOINSELECT d.Description as DispositionName, COUNT(c.DispositionID) AS DispositionCountFROM @Dispositions dLEFT OUTER JOIN @Calls c ON c.DispositionID = d.DispositionID AND c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description-- Results--DispositionName DispositionCount--Dispo 1 2--Dispo 2 0--Dispo 3 1--Dispo 4 0-- Query 2 -- INNER JOINSELECT d.Description as DispositionName, COUNT(c.DispositionID) AS DispositionCountFROM @Dispositions dINNER JOIN @Calls c ON c.DispositionID = d.DispositionIDWHERE c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description-- Results--DispositionName DispositionCount--Dispo 1 2--Dispo 3 1 |
 |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2008-12-03 : 17:23:24
|
Yes. I have never had a doubt.But I think it is not a good idea to say something like "use a left join for better performance" because in this case it isn't.Webfred No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-03 : 17:23:34
|
Not true. The original query will return zero counts; an INNER JOIN operation will exclude zero counts. I submit the following code for your review:DECLARE @Dispositions TABLE (Description VARCHAR(10)); DECLARE @Calls TABLE (DateLogged DATETIME, DispositionID VARCHAR(10)); INSERT INTO @Dispositions(Description)SELECT 'A'UNION ALLSELECT 'B'UNION ALLSELECT 'C'UNION ALLSELECT 'D'INSERT INTO @Calls(DateLogged, DispositionID)SELECT '10-01-2008', 'A'UNION ALLSELECT '10-04-2008', 'B'UNION ALLSELECT '10-05-2008', 'B'UNION ALLSELECT '11-10-2008', 'C'UNION ALLSELECT '12-01-2008', 'D'UNION ALL SELECT '12-05-2008', 'D'--This was the accepted solutionSELECTDescription as DispositionName,(SELECT Count(*) FROM @Calls c WHERE c.DispositionID = d.Description AND c.DateLogged > '10/3/2008' AND c.DateLogged <= '12/3/2008')FROM @Dispositions d--This was my solutionSELECT d.Description as DispositionName, COUNT(c.DispositionID)FROM @Dispositions dLEFT OUTER JOIN @Calls c ON c.DispositionID = d.Description AND c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description--This was your suggestion SELECT d.Description as DispositionName, COUNT(c.DispositionID)FROM @Dispositions dLEFT OUTER JOIN @Calls c ON c.DispositionID = d.DescriptionWHERE c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description--This is you suggestion using an INNER JOINSELECT d.Description as DispositionName, COUNT(c.DispositionID)FROM @Dispositions dINNER JOIN @Calls c ON c.DispositionID = d.DescriptionWHERE c.DateLogged BETWEEN '10/3/2008' AND '12/3/2008'GROUP BY d.Description As you can see if you run this, the first query was the accepted answer; the second query was my original response (sans a typo). The third query moved the ON clause to the WHERE clause, which produced identical results as the 4th query, which is an inner join operation vs. an outer join. The first two produce identical results. The last two do not. SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-03 : 17:28:37
|
quote: I think it is not a good idea to say something like "use a left join for better performance" because in this case it isn't
A left join operation is generally better performance that a subselect. Do you disagree? SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2008-12-03 : 17:32:11
|
OK in consideration of zero-counts you are right .GreetingsWebfred No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2008-12-03 : 17:36:25
|
quote: A left join operation is generally better performance that a subselect. Do you disagree?
Not in general because the optimizer is good enough to make it perform very well.Subselects are today not generally bad.Webfred No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-03 : 17:52:29
|
Well I think that this is a textbook case where a left join operation is called and optimized for, but I have no intention of setting up a performance analysis between subselects and left joins. I think the best solution here is to agree to disagree. :) SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2008-12-04 : 01:24:56
|
What if DispositionID is not unique? Then LEFT JOIN will return the wrong count number. E 12°55'05.63"N 56°04'39.26" |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-04 : 09:53:40
|
The original query (and your original solution) would have similarly skewed results at that point, I believe. Can you give a dataset where the results would be different? SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2008-12-04 : 10:04:54
|
We have no idea about the DDL. Is DispositionID unique?DECLARE @Dispositions TABLE ( DispositionID INT )INSERT @DispositionsSELECT 1 UNION ALLSELECT 1 UNION ALLSELECT 2 UNION ALLSELECT 3 UNION ALLSELECT 4DECLARE @Calls TABLE ( DispositionID INT )INSERT @CallsSELECT 1 UNION ALLSELECT 1 UNION ALLSELECT 1 UNION ALLSELECT 1 UNION ALLSELECT 1 UNION ALLSELECT 2 UNION ALLSELECT 3 UNION ALLSELECT 4-- PesoSELECT d.DispositionID, (SELECT COUNT(*) FROM @Calls AS c WHERE c.DispositionID = d.DispositionID) FROM @Dispositions AS d-- jholovacsSELECT d.DispositionID, COUNT(c.DispositionID)FROM @Dispositions AS dLEFT JOIN @Calls AS c ON c.DispositionID = d.DispositionIDGROUP BY d.DispositionID E 12°55'05.63"N 56°04'39.26" |
 |
|
|
jholovacs
Posting Yak Master
163 Posts |
Posted - 2008-12-04 : 10:20:58
|
hmmm.... very good. You're right, I had assumed DispositionID was unique. If it is not, the left join version will require some sort of unique identifier to factor in, unless the Dispositions table is filtered beforehand.I think the DispositionID field being unique is a fair assumption, but you're quite right that the qualification needs to be made. SELECT TOP 1 w.[name]FROM dbo.women wINNER JOIN dbo.inlaws i ON i.inlaw_id = w.parent_idWHERE i.net_worth > 10000000 AND i.status IN ('dead', 'dying') AND w.husband_id IS NULLORDER BY w.hotness_factor DESC |
 |
|
|
|