Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

count in LEFT JOIN and WHERE

I have a little problem with a left join where I want a list of designs and on each design I want to display how many comments each design have.

I am using a LEFT JOIN

SELECT ds.*, count(com.comment) AS countcom FROM tdic_designs ds 
LEFT JOIN tdic_comments com ON (com.design_id = ds.id) 
WHERE ds.approved = 1 AND ds.hidden = 0 AND com.approved = 1 
GROUP BY ds.id 
ORDER BY ds.date_added ASC

But that doesn't work as it only displays one design which have 1 comment, but I have two designs in the table, where the second design doesn't have a comment.

If I change the SQL to

SELECT ds.*, count(com.comment) AS countcom FROM tdic_designs ds 
LEFT JOIN tdic_comments com ON (com.design_id = ds.id) 
GROUP BY ds.id, com.approved, ds.approved 
ORDER BY ds.date_added ASC

That is removing the WHERE clause. But that is bad as it will select both designs and comments that haven't been approved.

What do I miss / do wrong?

like image 435
Morten Hagh Avatar asked Jun 08 '12 12:06

Morten Hagh


People also ask

How does left join with WHERE clause works?

Left join returns all values from the right table, and only matching values from the left table. ID and NAME columns are from the right side table, so are returned. Score is from the left table, and 30 is returned, as this value relates to Name "Flow". The other Names are NULL as they do not relate to Name "Flow".

WHERE and left join in SQL?

The LEFT JOIN keyword returns all records from the left table (table1), and the matching records from the right table (table2). The result is 0 records from the right side, if there is no match.

WHERE vs left outer join?

There really is no difference between a LEFT JOIN and a LEFT OUTER JOIN. Both versions of the syntax will produce the exact same result in PL/SQL. Some people do recommend including outer in a LEFT JOIN clause so it's clear that you're creating an outer join, but that's entirely optional.

Can LEFT join increase row count?

Left Outer Join returns all of the rows in the current data and all the data from the matching rows in the joined data, adding rows when there is more than one match. This can result in an expanded row count.


2 Answers

Move all filters on comments to the ON clause:

SELECT  ds.*, COUNT(com.design_id) AS countcom
FROM    tdic_designs ds
LEFT JOIN
        tdic_comments com
ON      com.design_id = ds.id
        AND com.approved = 1 
WHERE   ds.approved = 1
        AND ds.hidden = 0
GROUP BY
        ds.id
ORDER BY
        ds.date_added ASC
like image 153
Quassnoi Avatar answered Sep 30 '22 12:09

Quassnoi


The problem is that when you include com.approved = 1 in the WHERE clause, it filters out any rows where com.approved is NULL -- meaning all the rows where no match was found in the outer table.

As suggested by others, you can fix this by moving that condition to the ON clause, but I don't really like that since it's not a join condition.

I would move the filters on the outer table into an inline view

SELECT ds.*, count(com.comment) AS countcom FROM tdic_designs ds 
LEFT JOIN (SELECT * FROM tdic_comments com WHERE com.approved = 1) com
ON (com.design_id = ds.id) 
WHERE ds.approved = 1 AND ds.hidden = 0 
GROUP BY ds.id 
ORDER BY ds.date_added ASC
like image 45
Dave Costa Avatar answered Sep 30 '22 11:09

Dave Costa