2012-06-08 11 views
6

Tengo un pequeño problema con una combinación de la izquierda donde quiero una lista de diseños y en cada diseño quiero mostrar cuántos comentarios tiene cada diseño.cuente en LEFT JOIN y WHERE

estoy usando un 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 

Pero eso no funciona, ya que sólo muestra un diseño que tiene 1 comentario, pero tengo dos diseños en la tabla, en el que el segundo diseño no lo hace tener un comentario

Si cambio el SQL para

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 

Esa es la eliminación de la cláusula WHERE. Pero eso es malo, ya que seleccionará tanto diseños como comentarios que no hayan sido aprobados.

¿Qué extraño/hago mal?

+0

'MySQL', supongo? – Quassnoi

Respuesta

8

Mover todos los filtros en los comentarios a la cláusula 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

¡Funciona como un regalo! ¡Muchas gracias! –

3

Cuando se utiliza la cláusula WHERE, estas restricciones son aplicadas a las filas que son proporcionados por los left join s. Por lo tanto, algunas filas se eliminan si no están de acuerdo con las restricciones.

Lo que debe hacer es poner esas restricciones en la cláusula ON y debería funcionar, de modo que si no funciona, muestra NULL en lugar de eliminar la fila.

Algo como esto:

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 

Otro problema está utilizando ds.* en el SELECT cuando sólo tiene ds.id en el group BY.

+0

Gracias por esto :) –

+0

@MortenHagh no hay problema, si funciona, no se olvide de aceptar la respuesta :) –

0

El problema es que cuando se incluye com.approved = 1 en la cláusula WHERE, se filtra cualquier filas donde com.approved es NULL - lo que significa que todas las filas donde no se encontró ninguna coincidencia en la tabla externa.

Según lo sugerido por otros, puede solucionar esto moviendo esa condición a la cláusula ON, pero realmente no me gusta porque no es una condición de unión.

me movería los filtros en la tabla externa en una vista en línea

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

Esto afectaría gravemente el rendimiento en 'MySQL'. – Quassnoi

+0

@DaveCosta solución muy pobre .. –

+0

@ aF.why? Si quiere decir por la misma razón que lo indicó Quassnoi, es posible que tenga razón, pero la pregunta no especificaba MySQL. En Oracle, no esperaría ningún problema de rendimiento con esto. –