2009-06-28 14 views
13

Primero - disculpas por el título difuso, no pude encontrar uno mejor.SQL: tabla Many-To-Many Y consulta

I tienen mesa con la estructura siguiente (simplificación):

EmpID DeptID 

1  1 
1  2 
2  1 
3  2 
4  5 
5  2 

Esta tabla representa una relación de muchos a muchos.

Estoy interesado en encontrar todos los EmpIDs que están relacionados con un grupo específico de DeptIDs, por ejemplo, quiero todos los EmpIDs que están relacionados con DeptIDs 1, 2 y 3. Tenga en cuenta que es una relación AND y no un O relación. Para mi caso, el EmpID puede estar relacionado con DeptID adicionales además de 1, 2 y 3 para que sea una respuesta válida.

Cambia el número de DeptIDs que me interesan (es decir, puedo querer EmpIDs que están relacionados con DeptID 3 y 5, o puedo desear los EmpIDs relacionados con DepIDs 2, 3, 4, 5, 6, 7)

Cuando intento abordar este problema me encuentro creando un JOIN por DepID o una subconsulta por DeptID. Esto significaría que tengo que generar una nueva consulta por el número de DeptIDs contra los que estoy probando. Obviamente, preferiría tener una consulta estática con un parámetro o conjunto de parámetros.

Estoy trabajando sobre SQL Server y MySQL (desarrollando en paralelo dos versiones de mi código).

¿Alguna idea?

Respuesta

14

Estoy asumiendo que usted quiere encontrar a los empleados que están en TODO de los departamentos especificados y no sólo los empleados que están en CUALQUIER de los departamentos, lo cual es una consulta mucho más fácil.

SELECT EmpID 
FROM mytable t1 
JOIN mytable t2 ON t1.EmpID = t2.EmpID AND t2.DeptID = 2 
JOIN mytable t3 ON t2.EmpID = t3.EmpID AND t3.DeptID = 3 
WHERE DeptID = 1 

voy a anticiparse a lo inevitable sugerencia de que vendrá a utilizar la agregación:

SELECT EmpID 
FROM mytable 
WHERE DeptID IN (1,2,3) 
GROUP BY EmpID 
HAVING COUNT(1) = 3 

resistir esa tentación. Es significativamente más lento. Un escenario similar a este surgió en SQL Statement - “Join” Vs “Group By and Having” y la segunda versión fue, en ese segundo, aproximadamente veinte veces más lenta.

También le sugiero que consulte Database Development Mistakes Made by AppDevelopers.

3

me gustaría empezar desde algo como:

SELECT EmpID, COUNT(*) AS NumDepts 
FROM thetable 
WHERE DeptID IN (1, 2, 3) 
GROUP BY EmpId 
HAVING COUNT(*) == 3 

por supuesto, que el 3 en la última línea siempre habría la longitud de la secuencia de identificadores de departamento se esté examinando (por lo que para (2,3,4,5,6,7) sería 6). Esta es una forma natural de expresar "empleados conectados a todos estos departamentos".

Editar: Veo una nota en otra respuesta sobre problemas de rendimiento. He intentado este enfoque en SQLite y PostgreSQL, con los índices apropiados, y parece que está funcionando bien y con el uso adecuado de todos los índices; y en MySQL 5.0, donde debo admitir que el rendimiento no fue tan bueno en ninguna parte.

Sospecho (sin la oportunidad de comparar este en un trillón de motores más ;-) que otros motores SQL realmente buenos (como SQL Server 2008, Oracle, IBM DB2, el nuevo Ingres de código abierto ...) también optimizará esta consulta, mientras que otros mediocres (no se puede pensar en ninguno con una popularidad cercana a la de MySQL) no lo harán.

Así que, sin duda, su respuesta favorita dependerá de qué motores realmente le interesen (esto me lleva al tiempo, hace más de una década, cuando mis responsabilidades incluían administrar el equipo que mantenía un componente que se suponía que proporcionaba consultas de alto rendimiento en más de media docena de motores dispares: ¡hablemos de trabajos de pesadilla ...! -).

Cuestiones relacionadas