EXISTS・NOT EXISTS・全称量化パターンを完全習得
外側クエリの行を1行ずつ取り出し、その値を使ってサブクエリを実行する手法。サブクエリが外側クエリの列を参照する点が通常のサブクエリと異なる。
| 通常サブクエリ | 相関サブクエリ | |
|---|---|---|
| 実行回数 | 1回だけ | 外側の行数分だけ繰り返す |
| 外側への依存 | なし(独立) | あり(外側の列を参照) |
| 性能 | 一般に速い | 大量データでは遅くなりやすい |
| 用途 | 固定条件での絞り込み | 行ごとに動的に条件が変わる場合 |
-- 外側クエリの e1.部署ID を内側が参照する(相関サブクエリ) SELECT e1.氏名, e1.部署ID, e1.給与 FROM 社員 e1 WHERE e1.給与 = ( SELECT MAX(e2.給与) FROM 社員 e2 WHERE e2.部署ID = e1.部署ID -- ← 外側の e1.部署ID を参照 );
EXISTSはサブクエリが1行でも返せば TRUE。IN より大量データで高速になることが多い。
-- 注文履歴がある顧客だけを取得 SELECT c.顧客名 FROM 顧客 c WHERE EXISTS ( SELECT 1 FROM 注文 o WHERE o.顧客ID = c.顧客ID -- ← 外側の c.顧客ID を参照 );
-- NOT EXISTS:注文履歴がない顧客を取得 SELECT c.顧客名 FROM 顧客 c WHERE NOT EXISTS ( SELECT 1 FROM 注文 o WHERE o.顧客ID = c.顧客ID );
「全ての科目で合格した学生」のような全称量化は SQL に FOR ALL がないため、二重否定で表現する。
-- 全科目を受験した学生(科目が存在して、その学生が未受験の科目がない) SELECT DISTINCT s.学生ID, s.氏名 FROM 学生 s WHERE NOT EXISTS ( SELECT 1 FROM 科目 sub WHERE NOT EXISTS ( SELECT 1 FROM 受験 r WHERE r.学生ID = s.学生ID AND r.科目ID = sub.科目ID ) );
-- EXISTS を JOIN で書き換え(EXISTS の方が最適化されやすい場合も) SELECT DISTINCT c.顧客名 FROM 顧客 c JOIN 注文 o ON o.顧客ID = c.顧客ID;
読了ボタンを押すとトップページの進捗に反映されます