2009-06-28 24 views
13

ファジータイトルの最初の謝罪、私はより良いものを見つけることができませんでした。SQL:多対多テーブルANDクエリ

Iは、以下の構造(単純化)を持つテーブルを持っている:

EmpID DeptID 

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

このテーブルは、多対多の関係を表しています。

DeptIDの特定のグループに関連するすべてのEmpIDを検索することに興味があります。たとえば、DeptID 1,2,3に関連するすべてのEmpIDが必要です。AND関係であり、 OR関係。私の場合、EmpIDは有効な回答であるために1,2,3以外の追加のDeptIDに関連している可能性があります。

変更に興味のあるDeptIDの数(DeptID 3と5の両方に関連するEmpIDが必要な場合や、DepID 2,3,4,5,6,7に関連するEmpIDが必要な場合があります) )。

私はこの問題にアプローチしようとすると、DepidごとにJOINを作成するか、DeptIDごとにサブクエリを作成します。これは、テスト対象のDeptIDの数ごとに新しいクエリを生成する必要があることを意味します。私は明らかにパラメータまたはパラメータのセットを持つ静的クエリを持つことを好むでしょう。

私はSQL ServerとMySQLの両方(私のコードの2つのバージョンを並行して開発しています)で作業しています。

アイデア?

答えて

14

私はあなたが指定された部署のALLにあり、はるかに容易にクエリです部署のANYであるだけでなく、従業員の従業員を見つけたいと仮定しています。

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

その誘惑に抵抗:

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 

は私が集約を使用するために来る必然的な提案を先取りするつもりです。それは のかなりのです。これと同様のシナリオが SQL Statement - “Join” Vs “Group By and Having”にあり、2番目のバージョンは約 約20倍遅いでした。

私はまた、Database Development Mistakes Made by AppDevelopersを見ることをお勧めします。

3

私のようなものから始めたい:それは次のようになり(2,3,4,5,6,7)のためのように、最後の行の3は常にあなたがチェックしている部門ID(のシーケンスの長さになると、

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

6)。これは、「これらすべての部門に関係する従業員」を表現する自然な方法の1つです。

編集:私は、パフォーマンスの問題についての別の回答のノートを見ています。このアプローチをSQLiteとPostgreSQLで適切なインデックスで試してみました。そしてMySQL 5.0では、私はパフォーマンスがどこでも良いと認めなければなりませんでした。

他の本当に良いSQLエンジン(SQL Server 2008、Oracle、IBM DB2、新しいオープンソースIngresなど)がベンチマークする機会はありません。)はこのクエリをうまく最適化しますが、他の平凡なもの(MySQLに近いところで人気があるとは思えません)はそうではありません。

あなたが本当に気にしているエンジンによって、お気に入りの答えが変わることは間違いありません(これは、10年以上前から私が責任を負っている時間に戻っています。異種のエンジンの6つ以上の上でうまく実行しているクエリ - 悪夢の仕事について話してください... - )。