中学理科1627252 views
いろは2991619 views
世界の国561222 views
中学英語809327 views
雑学1472809 views
ヒストリア285220 views
高校倫理1434489 views
高校物理158525 views
教育149021 views
高校化学2914902 views

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 問題だけは覚えておきましょう。