2012-06-08 4 views
6

У меня есть небольшая проблема с левым объединением, где мне нужен список дизайнов и по каждому дизайну я хочу показать, сколько комментариев у каждого дизайна есть.count в LEFT JOIN и WHERE

Я использую 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 

Но это не работает, как он отображает только один дизайн, который есть 1 комментарий, но у меня есть два проекта, в таблице, где вторая конструкция не есть комментарий.

Если изменить SQL в

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 

Это является удаление ИНЕКЕ. Но это плохо, поскольку он будет выбирать как проекты, так и комментарии, которые не были одобрены.

Что я пропускаю/делаю неправильно?

+0

'MySQL', я полагаю? – Quassnoi

ответ

8

Переместить все фильтры на комментарии к статье ON:

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 
+0

Работает как лакомство! Большое спасибо! –

3

При использовании пункта WHERE, эти ограничения должны применяться к строкам, которые предоставляются в left join с. Таким образом, некоторые строки удаляются, если они не согласуются с ограничениями.

Что вам нужно сделать, это положить эти ограничения в предложении ON, и он должен работать так, если он не работает, он показывает NULL вместо удаления строки.

Что-то вроде этого:

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

Другая проблема заключается в использовании ds.* в SELECT, когда у вас есть только ds.id на group BY.

+0

Спасибо за это :) –

+0

@MortenHagh не проблема, если он работает, не забудьте принять ответ :) –

0

Проблема заключается в том, что когда вы включаете com.approved = 1 в предложение WHERE, он отфильтровывает любые строки, где com.approved is NULL - означает все строки, в которых не было найдено совпадений во внешней таблице.

Как было предложено другими, вы можете исправить это, переместив это условие в пункт ON, но мне это не очень нравится, поскольку это не условие соединения.

Я бы переместить фильтры на внешней таблицы в вложенное представление

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 
+0

Это сильно ухудшит производительность на 'MySQL'. – Quassnoi

+0

@DaveCosta очень плохое решение .. –

+0

@ aF.why? Если вы имеете в виду по той же причине, что и Quassnoi, вы можете быть правы, но вопрос не задал MySQL. В Oracle я бы не ожидал каких-либо проблем с производительностью. –