WHERE句のサブクエリ

このレッスンで分かること

  • 単一値返却なら = < >、複数値返却は IN ANY ALL EXISTS を使い分けます
  • NOT IN は NULL に弱い、NOT EXISTS で書き換えるのが安全
  • 最小例は WHERE id IN (SELECT customer_id FROM orders);

WHERE句のサブクエリ とは

WHERE句の中でサブクエリを使う方法を、実践的な例を通して学びます。本レッスンでは、WHERE句のサブクエリ の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

「他のテーブルに該当がある行」「集計結果と比較した行」「最大値の行」を絞り込むのは、SQL を書く上で日常的に発生します。WHERE 句にサブクエリを書けば、こうした条件をスマートに表現できます。本レッスンでは 単一値で比較する場合=, <, >)と、複数値で比較する場合IN, ANY, ALL, EXISTS)の使い分けを学びます。とくに『複数行を返すサブクエリ= を使うと壊れる』というハマりポイントは、現場でもよく見るミスなので押さえておきましょう。

構文・キーワード解説

WHERE 句のサブクエリには次の比較演算子が使えます。

SQL クエリ

-- 単一値を返すサブクエリ WHERE column = (SELECT ...) WHERE column > (SELECT AVG(price) FROM ...) -- 複数値を返すサブクエリ WHERE column IN (SELECT ...) WHERE column NOT IN (SELECT ...) WHERE column > ANY (SELECT ...) -- 一つでも該当があれば真 WHERE column > ALL (SELECT ...) -- 全てに該当する場合のみ真 WHERE EXISTS (SELECT 1 FROM ... WHERE ...)

ステップごとの動作

非相関サブクエリは「内側を 1 回実行 → 結果を外側の比較値として使う」というシンプルな流れです。

diagram (will load when visible)

単一値と複数値の違い

サブクエリが返す行数で書き方が変わります。

返ってくる行使える演算子失敗するパターン
1 行 1 列=, <, >, <=, >=, <>0 行のときは NULL になり常に false
複数行 1 列IN, ANY, ALL, EXISTS= を使うと実行時エラー
1 行 N 列(行コンストラクタ)(a, b) = (SELECT a, b ...)列数不一致でエラー

代表例

IN で「注文がある顧客」を取り出す

SQL クエリ

SELECT id, name FROM customers WHERE id IN (SELECT DISTINCT customer_id FROM orders);

orders テーブルに登場する customer_id をサブクエリで集め、その集合に含まれる顧客だけを返します。

> ALL で全カテゴリの最高値より高い商品

SQL クエリ

SELECT name, price FROM products WHERE price > ALL ( SELECT MAX(price) FROM products WHERE category <> '家電' GROUP BY category );

家電以外の各カテゴリの最高価格すべてを上回る価格、という条件です。ANY だと「いずれか 1 つ以上」になる点と対比して覚えると整理しやすくなります。

EXISTS で「注文を持っている顧客」を取り出す

SQL クエリ

SELECT id, name FROM customers c WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.customer_id = c.id );

EXISTS は「サブクエリが 1 行でも返したら真」という意味で、JOIN しなくても存在チェックができます。重複が出ないのもメリットです。

NOT IN の落とし穴

注意 サブクエリの結果に NULL が混ざると、NOT INすべての行が false になります。customer_id に NULL を許容している場合は NOT EXISTS で書き換えるのが安全です。

SQL クエリ

-- NULL が含まれていても安全 SELECT id, name FROM customers c WHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.customer_id = c.id );

IN と EXISTS の使い分け

結果が同じになることが多い IN と EXISTS ですが、内部の動作と得意分野は微妙に違います。

  • IN: 内側で値の集合を作ってから、外側と突き合わせる。集合が小さければ高速
  • EXISTS: 外側の各行に対し、内側を 1 件でも見つけたら打ち切る。短絡評価が効く

SQL クエリ

-- IN 形式 SELECT id, name FROM customers WHERE id IN (SELECT customer_id FROM orders WHERE amount >= 5000); -- EXISTS 形式 SELECT id, name FROM customers c WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.customer_id = c.id AND o.amount >= 5000 );
観点INEXISTS
内部動作集合を作って突き合わせ行ごとに 1 件見つけたら打ち切り
NULL に強い弱い (NOT IN で詰む)強い
相関サブクエリ不要必要
読みやすさ集合の所属を表現「存在するか」を直球で表現

「サブクエリが返す行が少ない」「重複を出したくない」「外側と相関させたい」場合は EXISTS が便利。単純に集合に含まれるかだけ確認したいなら IN のほうが読みやすい。

IN と EXISTS は等価でないことがある。NULL を含む場合と相関の有無で挙動が変わるため、相手側の前提を確認してから選ぶ。

この章のポイント

ここまでの要点 単一値は = 系、複数値は IN / ANY / ALL / EXISTS。NULL を含むなら NOT EXISTS が安全。INEXISTS は等価でない場面があるので前提を確認。

まとめ

  • 単一値を返すサブクエリには = < > などが使える
  • 複数値を返すサブクエリには IN ANY ALL EXISTS を使う
  • EXISTS は重複を生まず、NULL 混在にも強い
  • NOT IN は NULL に弱いので、可能な限り NOT EXISTS を選ぶ

次のレッスン

次は FROM句のサブクエリ です。FROM句でサブクエリを使う方法を学習し、複雑なデータ抽出に挑戦します。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. WHERE サブクエリ の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. WHERE サブクエリ とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

テーブル構造

schema.sql

CREATE TABLE customers ( id INT PRIMARY KEY, name VARCHAR(40) ); CREATE TABLE orders ( id INT PRIMARY KEY, customer_id INT, amount INT ); INSERT INTO customers VALUES (1, '佐藤'), (2, '鈴木'), (3, '田中'), (4, '高橋'), (5, '伊藤'); INSERT INTO orders VALUES (101, 1, 3000), (102, 1, 1500), (103, 2, 8000), (104, 4, 5000);

期待される出力

idname
1佐藤
2鈴木
4高橋

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...