tags:

views:

43

answers:

2

This is a query that is executed without problem with MySql 5.0.51:

SELECT cc_split.idSplit,
       count( voteup.vote),
       count( votedown.vote)
FROM cc_split
LEFT JOIN cc_split_usager AS voteup ON voteup.idSplit = cc_split.idSplit
      AND voteup.vote >0
LEFT JOIN cc_split_usager AS votedown ON votedown.idSplit = cc_split.idSplit
      AND votedown.vote <0
WHERE cc_split.isArchived = false
GROUP BY cc_split.idSplit
LIMIT 0, 30

The problem is with the COUNT that doesn't display what I would like to have. Has you can see, it takes the cc_ split_ usager and should count the number of vote that is positive and on the other hand count the amount of vote that is negative. The code above display the number 2 upvote and 2 downvote when in fact it should be 2 upvote and 1 downvote. What is the trick to have in a single SQL query the number of upvote and downvote.

The tables look like:

cc_split:
-idSplit
-...
cc_split_usager:
-idSplit
-vote (can be +1 or -1)
-...

Any hint for me?

+1  A: 

Try:

SELECT s.idSplit, 
    count(case when v.vote > 0 then 1 else null end) as VoteUp, 
    count(case when v.vote < 0 then 1 else null end) as VoteDown 
FROM cc_split s
LEFT JOIN cc_split_usager AS v ON v.idSplit = s.idSplit
WHERE s.isArchived = false
GROUP BY s.idSplit
LIMIT 0, 30
RedFilter
+1 it works! Can you explain me why I require to have a condition in the count? If you can I will automaticly accept you as answer.
Daok
COUNT will not count NULL values, so the condition says if greater than 1 (for up vote) return a 1 (any value would do really), else return a NULL. The CASE is equivalent to an IF or a SWITCH-type statement depending upon how it is used.
RedFilter
It's because `count (voteup)` and `count(votedown)` give you the same number as `count(*)`, which is the number of rows in the join per group.
Jeremy Smyth
@Orbman, yr solution would also work and be a bit terser (shorter) without the 'Else Null' portion, as that is the default else value
Charles Bretana
+1  A: 

try this:

SELECT s.idSplit, 
    Sum( Case When vote > 0 Then 1 Else 0 End) UpVotes,
    Sum( Case When vote < 0 Then 1 Else 0 End) DownVotes
FROM cc_split s       
   LEFT JOIN cc_split_usager v 
      ON v.idSplit = s.idSplit        
WHERE s.isArchived = false        
GROUP BY s.idSplit        
LIMIT 0 , 30
Charles Bretana
@OrbMan's solution works because COunt does not 'count' null values. and the rows in the result set being aggregated where the vote value is < 0 will ahve null values for the case expression. My works because I'm adding up the values, and those rows will ghave zero for the case expression.
Charles Bretana
I give you +1 (I had to remove 2 parentheses to make it works). But OrbMan answer has been the first one with more explication so he deserved the answer. Thanks +1
Daok
Thx for the additionnal information ! I understand more how the SUM and COUNT works with both of your example :)
Daok
@Daok, I see! I typo'd the extra )s... Thx for the edit!
Charles Bretana