2009-06-28 22 views
13

Prima - scuse per il titolo fuzzy, non ho trovato uno migliore.SQL: tabella Many-To-Many E query

devo tabella con la seguente struttura (semplificazione):

EmpID DeptID 

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

Questa tabella rappresenta una relazione molti-a-molti.

Sono interessato a trovare tutti gli EmpID correlati a un gruppo specifico di IDENTID, ad esempio, desidero tutti gli EmpID correlati a DeptID 1, 2 e 3. Notare che si tratta di una relazione AND e non di un O relazione. Per il mio caso, l'EmpID può essere correlato a ulteriori identificativi oltre a 1, 2 e 3 perché sia ​​una risposta valida.

Il numero di IDENTIFICAZIONE Sono interessato a modifiche (ad esempio, potrei desiderare EmpIDs che sono correlati a DeptID 3 e 5, o Potrei volere EmpIDs relativi ai DepIDs 2, 3, 4, 5, 6, 7).

Quando provo ad avvicinarmi a questo problema, mi trovo a creare un JOIN per DepID o una sottoquery per DeptID. Ciò significherebbe che devo generare una nuova query per il numero di identificatori che sto testando. Ovviamente preferirei avere una query statica con un parametro o una serie di parametri.

Sto lavorando su SQL Server e MySQL (sviluppando in parallelo due versioni del mio codice).

Qualche idea?

risposta

14

sto supponendo che si desidera trovare i dipendenti che si trovano in TUTTI dei dipartimenti specifici e non solo i dipendenti che si trovano in QUALSIASI dei dipartimenti, che è una query molto più facile.

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 

ho intenzione di anticipare il suggerimento inevitabile che arriva a utilizzare l'aggregazione:

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

resistere a quella tentazione. È significativamente più lento. Uno scenario simile a questo è venuto in SQL Statement - “Join” Vs “Group By and Having” e la seconda versione era, in quel secondo, su venti volte più lento.

Vorrei anche suggerire di guardare Database Development Mistakes Made by AppDevelopers.

3

mi piacerebbe iniziare da qualcosa come:

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

naturalmente, che il 3 nell'ultima riga sarebbe sempre la lunghezza della sequenza di ID reparto si sta controllando (quindi per (2,3,4,5,6,7) sarebbe 6). Questo è un modo naturale per esprimere "dipendenti collegati a tutti questi dipartimenti".

Modifica: Vedo una nota in un'altra risposta sui problemi di prestazioni - Ho provato questo approccio in SQLite e PostgreSQL, con indici appropriati, e sembra che stia funzionando bene e con l'uso appropriato di tutti gli indici citati; e in MySQL 5.0, dove devo ammettere che le prestazioni non sono mai state così buone.

Sospetto (senza un'opportunità di confrontare questo su un miliardo di più motori ;-) altri motori SQL davvero buoni (come SQL Server 2008, Oracle, IBM DB2, il nuovo Ingres open-source ...ottimizzerà anche questa query, mentre altri mediocri (non riesco a pensare a nessuno con una popolarità da nessuna parte vicino a MySQL) non lo faranno.

Quindi, senza dubbio la tua risposta preferita dipenderà da quali motori ti interessano veramente (questo mi riporta indietro al tempo, oltre un decennio fa, quando le mie responsabilità includevano la gestione del team che gestiva un componente che avrebbe dovuto fornire domande ben eseguite su più di una mezza dozzina di motori disparati - parla di lavori da incubo ...! -).