NOT EXISTS (subquery)
サブクエリの結果セットに行がない場合、述語はTRUEを返します。一致する行が見つかるとFALSEを返します。
本質的に、クエリは尋ねています
Employeeの各行について...Projectテーブルの各行をチェックして、Assignedテーブルに、Employee行のempidと一致するempidとinの行と一致するprojidを持つ行の行があるかどうかを確認します。プロジェクトテーブル。
Employeeからの行は、一致する行が見つからない場合にのみ返されます。
サブクエリのSELECTリストの式は重要ではないことに注意してください。チェックされているのは、そのサブクエリが1つ(または複数)の行を返すかどうかだけです。通常、SELECTリストではリテラル1を使用します。これは、チェックしているのは行が見つかったかどうかであることを思い出させてくれます。)
私は通常、次のようなスタイルでクエリを記述します。
SELECT e.empname
FROM Employee e
WHERE NOT EXISTS
( SELECT 1
FROM Project p
WHERE NOT EXISTS
( SELECT 1
FROM Assigned a
WHERE a.empid = e.empid
AND a.projid = p.projid
)
)
そして、私は「SELECT 1
」を「1行を選択」と読みました)
そのクエリの結果セットは、基本的にこの(通常ははるかに効率の低い)クエリの結果セットと同等です。
SELECT e.empname
FROM Employee e
WHERE e.empid NOT IN
( SELECT a.empid
FROM Assigned a
JOIN Project p
ON a.projid = p.projid
WHERE a.empid IS NOT NULL
GROUP
BY a.empid
)
そのNOT IN
サブクエリを実行して何かが返されることを確認できるため、クエリは少し理解しやすくなります。(NOT EXISTSサブクエリについて混乱する可能性があるのは、SELECTリストに返される式は重要ではないということです。重要なのは、行が返されるかどうかです。)NOTINにはいくつかの「落とし穴」があります。本当に悪いパフォーマンスに加えてサブクエリ。サブクエリがNULL値を返さないように注意する必要があります。そうすると、NOT IN(NULL、...)がtrueを返すことはないからです。
アンチジョインパターンを使用して、同等の結果セットを返すこともできます。
SELECT e.empname
FROM Employee e
LEFT
JOIN ( SELECT a.empid
FROM Assigned a
JOIN Project p
ON a.projid = p.projid
WHERE a.empid IS NOT NULL
GROUP
BY a.empid
) o
ON o.empid = e.empid
WHERE o.empid IS NULL
そのクエリでは、empidで「一致」を探しています。LEFTキーワードは、一致しない行(JOINの左側のテーブル)も返すようにMySQLに指示します。これらの行については、一致する行があった場合に返されるはずだった列の値の代わりにNULL値が返されます。「トリック」は、一致したすべての行を破棄することです。これを行うには、一致した場合はNULLではない列のNULLをチェックします。
NOT EXISTS
述語を使用してこのクエリを作成する場合、実際には次のように作成することをお勧めします。
SELECT e.empname
FROM Employee e
WHERE NOT EXISTS
( SELECT 1
FROM Assigned a
JOIN Project p
ON a.projid = p.projid
WHERE a.empid = e.empid
)