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?
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".
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With