IN とサブクエリを組み合わせる
IN 演算子とサブクエリを組み合わせると、「別のテーブルから取得した値のリストに含まれるか」をチェックできます。
基本構文
SELECT * FROM テーブル
WHERE カラム IN (サブクエリ);サブクエリが返す複数の値のどれかに一致すれば TRUE になります。
具体例
「注文したことがあるユーザー」を取得するには、こう書きます。
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);サブクエリが注文テーブルから user_id の一覧を取得し、その中に含まれる users.id を持つ行だけが返ります。
固定値の IN との違い
固定値を使う IN は、値を直接書きます。
-- 固定値
SELECT * FROM users WHERE city IN ('東京', '大阪', '名古屋');
-- サブクエリ
SELECT * FROM users WHERE city IN (SELECT city FROM target_cities);サブクエリを使うと、条件を動的に取得できます。
NOT IN
NOT IN を使うと「含まれない」をチェックできます。
-- 注文したことがないユーザー
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM orders);NOT IN と NULL の罠
NOT IN を使うときは NULL に注意が必要です。サブクエリの結果に NULL が含まれていると、NOT IN は期待どおりに動きません。
-- orders.user_id に NULL があると、結果が 0 件になる可能性
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM orders);これは SQL の仕様です。NULL との比較は常に UNKNOWN になるため、NOT IN 全体が UNKNOWN になってしまいます。
サブクエリに NULL なし
正常に動作する
サブクエリに NULL あり
結果が 0 件になる可能性
回避するには、サブクエリで NULL を除外します。
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM orders WHERE user_id IS NOT NULL);または NOT EXISTS を使うほうが安全です。
SELECT * FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);パフォーマンスについて
IN とサブクエリの組み合わせは、サブクエリの結果が大きくなると遅くなることがあります。
小さい結果セット
IN + サブクエリでも問題ない
大きい結果セット
JOIN や EXISTS を検討したほうがよい
-- IN + サブクエリ
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
-- JOIN で書き換え(重複除去が必要)
SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id;IN とサブクエリは直感的でわかりやすい書き方ですが、NOT IN の NULL 問題だけは覚えておきましょう。












