Múltiples join y solución al encadenar LEFT JOINS
Escrito por Alex Barros Desde que publiqué el artículo de Inner Join para unir tablas y más especialmente el de Explicación visual de los SQL Join – Unir tablas con SQL me han consultado en muchos comentarios cómo hacer múltiples JOIN en una sóla consulta.
Hasta hoy no lo había necesitado, y nunca supe contestar. Hasta hoy.
Encadenar Joins es tan simple como ponerlos uno a continuación de otro.
ejemplo:
-
SELECT A.*, B.*, C.id FROM tabla_a A
-
INNER JOIN tabla_b B ON A.id = B.foo
-
LEFT JOIN tabla_c C ON A.id = C.bar
Y así sucesivamente. Puedes tener tantos joins como necesites, y si es necesario jugar con los paréntesis para cambiar la preferencia (por defecto MySQL lee de izquierda a derecha).
Pero una vez esto aclarado, me he encontrado con un problema. Lo que yo quería hacer es una serie de LEFT JOINs para consultar en una serie de tablas la cantidad (COUNT()) de registros de otras tablas que estaban asociados a la clave primaria de una tabla principal.
En mi caso concreto, tengo una serie de Rutas de bicicleta en una tabla, y en otras tablas satélite tengo almacenados los comentarios asociados a la ruta, las votaciones, los archivos adjuntos, etc… de modo que haciendo un COUNT en estas tablas para cada una de las claves primarias de la principal (Rutas) me saldría la cantidad asociada.
Así que hice algo como esto:
-
SELECT R.*, COUNT(C.id) comments, COUNT(S.id) saved, COUNT(V.id) votes, COUNT(P.id) photos, U.name owner, U.mail, U.about, U.image avatar, U.authority
-
-
FROM geo_routes R
-
LEFT JOIN geo_comments_routes C ON R.id = C.cid
-
LEFT JOIN geo_saved S ON R.id = S.route
-
LEFT JOIN geo_votes V ON R.id = V.route
-
LEFT JOIN geo_photos P ON R.id = P.route
-
LEFT JOIN geo_users U ON U.id = R.property
-
-
GROUP BY R.id
Pero esta consulta no daba valores correctos, sinó que en estos campos COUNT aparecía generalmente el mismo número replicado.
La solución es usar la cláusula DISTINCT en los COUNT, ya que en cada uno de los LEFT JOIN se están asociando muchos campos a cada registro de la tabla principal, y si no especificas el que te interesa cuántos DISTINTOS hay (y no sólo cuántos hay) te hincha la cifra o simplemente te la altera.
De modo que mi consulta ha quedado así:
-
SELECT R.*, COUNT(DISTINCT C.id) comments, COUNT(DISTINCT S.id) saved, COUNT(DISTINCT V.id) votes, COUNT(DISTINCT P.id) photos, U.name owner, U.mail, U.about, U.image avatar, U.authority
-
-
FROM geo_routes R
-
LEFT JOIN geo_comments_routes C ON R.id = C.cid
-
LEFT JOIN geo_saved S ON R.id = S.route
-
LEFT JOIN geo_votes V ON R.id = V.route
-
LEFT JOIN geo_photos P ON R.id = P.route
-
LEFT JOIN geo_users U ON U.id = R.property
-
-
GROUP BY R.id
Después he asociado a esta consulta una Vista, para poder tratarla como si fuera una tabla con esos campos ya incluidos.
Espero que estos consejos os puedan servir de mucho! A mi me ha costado mucho dar con las respuestas.
Categorias: Boozox |
8 comentarios »

Es una aplicación con mucho potencial, porque el de “usuarios de GPS con ganas de copartir rutas”, es un público que está ahí, que está esperando que le ofrezcas una buena solución. Además me encanta porque es una aplicación que realmente ayuda a la gente a conseguir lo que quiere, no es una banalidad 2.0 (que abundan mucho por la red).






Respeta el copyleft