重要 ⏱ 8分★★★★☆

相関サブクエリ

EXISTS・NOT EXISTS・全称量化パターンを完全習得

外側クエリの行を1行ずつ取り出し、その値を使ってサブクエリを実行する手法。サブクエリが外側クエリの列を参照する点が通常のサブクエリと異なる。

通常サブクエリ vs 相関サブクエリ
通常サブクエリ相関サブクエリ
実行回数1回だけ外側の行数分だけ繰り返す
外側への依存なし(独立)あり(外側の列を参照)
性能一般に速い大量データでは遅くなりやすい
用途固定条件での絞り込み行ごとに動的に条件が変わる場合
-- 外側クエリの e1.部署ID を内側が参照する(相関サブクエリ)
SELECT e1.氏名, e1.部署ID, e1.給与
FROM   社員 e1
WHERE  e1.給与 = (
  SELECT MAX(e2.給与)
  FROM   社員 e2
  WHERE  e2.部署ID = e1.部署ID  -- ← 外側の e1.部署ID を参照
);
内側のサブクエリは「e1 の現在行の部署ID と一致する社員の最大給与」を返す。これを外側の e1.給与 と比較。

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
);
NOT EXISTS は「全てのXについてYである」という全称量化の表現に使われる。試験の午後問題で頻出。

「全ての科目で合格した学生」のような全称量化は 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
  )
);
二重 NOT EXISTS は DB試験午後の定番。「未受験の科目が存在しない学生」=「全科目受験した学生」の論理を理解する。
-- EXISTS を JOIN で書き換え(EXISTS の方が最適化されやすい場合も)
SELECT DISTINCT c.顧客名
FROM   顧客 c
JOIN   注文 o ON o.顧客ID = c.顧客ID;
EXISTS は「存在確認だけ」なので先頭行が見つかった時点で内側処理を打ち切る(早期終了)。JOINと同結果になるが、EXISTS は重複を自動除去しない点に注意(DISTINCT が必要な場合もある)。

📝 理解度チェック

相関サブクエリが通常のサブクエリと異なる最大の特徴はどれか?
NOT EXISTS を使った二重否定が表現するのはどれか?
EXISTSが IN より有利になりやすいケースはどれか?

読了ボタンを押すとトップページの進捗に反映されます