2011-03-15 15 views
5

Volveré a publicar esta pregunta porque creo que la última vez que lo redacté estaba mal, y la solución que pensé que estaba funcionando no lo es.MySQL: muchos a muchos se unen donde no existe

Tengo 3 tablas: proyectos, servicios y recomendaciones. Las recomendaciones proporcionan la relación muchos a muchos entre Proyectos y Servicios, es decir, cada fila en Recomendaciones tiene un project_id y un service_id.

Digamos que hay 1000 proyectos y 5 servicios. No esperaría más de 5000 registros en mi tabla de Recomendaciones, pero casi seguramente menos (es decir, algunos proyectos no tienen recomendaciones de servicio). Por lo tanto, para el proyecto # 1, si se han recomendado los 5 servicios, que vería 5 filas en la tabla de recomendaciones como:

project_id service_id 
1   1 
1   2 
1   3 
1   4 
1   5 

Lo que estoy tratando de hacer es construir una consulta que me muestra lo que los proyectos no hacen tener todos los 5 servicios recomendados, y cuáles son. Así que digamos que el proyecto n. ° 1 solo tenía los primeros 3 servicios recomendados; el resultado de mi consulta que muestra cuáles faltan podría verse así:

project_id service_id 
1   4 
1   5 

¡Gracias!

+0

cuestión Anterior: http://stackoverflow.com/questions/ 5169625/sql-join-three-tables-combined-inner-left-outer-join – JNK

+2

Si hace referencia a una pregunta anterior de más de una hora, es bueno incluir un enlace, especialmente cuando dice que la respuesta anterior no lo hizo trabajo :) – JNK

+1

De hecho, lo siento! Tomó nota para referencia futura: P – David

Respuesta

5
Select P.project_id, S.service_id 
From Projects As P 
    Cross Join Services As S 
Where Not Exists (
        Select 1 
        From Recommendations As R1 
        Where R1.project_id = P.project_id 
         And R1.service_id = S.service_id 
        ) 

Otra variante que debe trabajar en MySQL

Select P.project_id, S.service_id 
From Projects As P 
    Cross Join Services As S 
Where (P.project_id, S.service_id) Not In (
              Select R1.project_Id, R1.service_id 
              From Recommendations As R1 
              ) 
+0

@Joe Stefanelli - En realidad, por lo que he leído es Inner Join que puede comportarse como una unión cruzada si no utiliza una cláusula On o una cláusula Where que une las claves. – Thomas

+0

@Joe Stefanelli: en los documentos, básicamente puede usar una combinación cruzada para comportarse como una unión interna si incluye una cláusula On o una cláusula Where. Esta bien. De cualquier manera, quiero el producto cartesiano que conseguiré sin un En o Donde. – Thomas

+0

@Thomas: estoy de pie (OK, estoy sentado) corregido. Dejaré caer el comentario y +1. –

2

ACTUALIZACIÓN ahora que leo la pregunta correctamente. Voy a seguir utilizando una combinación externa, pero sin sub-consulta este tiempo:

SELECT p.project_id,s.service_id 
FROM projects p 
cross join services s 
LEFT OUTER JOIN recommendations r on r.project_id = p.project_id and r.service_id = s.service_id 
WHERE r.project_id IS NULL 
+1

Se corrigió mi consulta ahora. –

+0

Gracias Ike! El tuyo también funcionó, pero se lo di a Thomas simplemente porque comencé a usar su solución primero. +1 – David

+0

No hay problema. Devolverán exactamente los mismos datos, pero le recomiendo que compare el rendimiento de las dos consultas. Espero que el mío sea al menos un 40% más rápido. –

1

Una opción bastante simplista es la siguiente:

select project_id, count(*) 
from recommendations 
group by project_id 
having count(distinct service_id) < (select count(*) from services) 
Cuestiones relacionadas