基本条件で絞る

IN・NOT INで候補を含める・除外したい

このページでできること

INは候補に一致する行、NOT INは候補から外れる行を探します。除外リストや比較する列にNULLがある場合は、結果が変わる点に注意します。

SQL例の例

SELECT name, department_id
FROM employees
WHERE department_id IN (1, 3)
ORDER BY id;

この例で使うサンプル表を見る共通の架空データと、練習用の表を確認します

全20項目で共通の架空データです。salary は月給(円)。NULL は未設定を表します。結果の小数点以下の表示桁数は実行環境により異なります。

employees

employees のサンプルデータ
idnamedepartment_idsalary
1佐藤1300000
2鈴木2400000
3佐々木1350000
4高橋2400000
5田中NULL250000
6伊藤3NULL

departments

departments のサンプルデータ
idname
1営業
2開発
3人事
4広報

employees.department_id が departments.id に対応します。表は説明用です。このサイト上でSQLは実行しません。

使い方を順番に確認する練習を始めるときは、この手順に沿って進めます

使い方

  1. 候補となる部署IDを調べる
  2. IN (1, 3) と書く
  3. 該当社員の名前と部署IDを確認する

結果の例

結果:3行
namedepartment_id
佐藤1
佐々木1
伊藤3
注意点

NULLは不明な値です。WHEREは条件がTRUE(真)の行だけを残し、FALSE(偽)とUNKNOWN(不明)は残しません。NOT INを付ければIN以外の全行になる、とは限りません。

NOT INとNULL:0件になる例と直し方

1. 営業部以外を探す:未設定の部署は含まれない

SELECT e.name, e.department_id
FROM employees AS e
WHERE e.department_id NOT IN (1)
ORDER BY e.id;

営業部IDは1です。部署2と3の3人が残ります。田中さんのNULLは1と違うと確定できないため、結果に含まれません。

1. 営業部以外を探す:未設定の部署は含まれない:3行
namedepartment_id
鈴木2
高橋2
伊藤3

2. 除外リストにNULLがあると0件になる

WITH excluded_departments (department_id) AS (
  VALUES (1), (NULL)
)
SELECT e.name, e.department_id
FROM employees AS e
WHERE e.department_id NOT IN (
  SELECT department_id FROM excluded_departments
)
ORDER BY e.id;

WITHはこのSELECT文の中だけで使う仮の一覧を作ります。除外候補は1とNULLです。部署1はFALSE、部署2・3や未設定はUNKNOWNになり、TRUEの行がないため0件です。構文エラーではありません。

2. 除外リストにNULLがあると0件になる:0行
namedepartment_id

3. 除外リストからNULLを取り除く

WITH excluded_departments (department_id) AS (
  VALUES (1), (NULL)
)
SELECT e.name, e.department_id
FROM employees AS e
WHERE e.department_id NOT IN (
  SELECT department_id FROM excluded_departments
  WHERE department_id IS NOT NULL
)
ORDER BY e.id;

内側のSELECTでNULLを取り除くと、除外候補は1だけになります。ただし社員側の部署NULLは依然として残りません。この例では「未設定の除外候補は無視する」という業務上のルールを採用しています。

3. 除外リストからNULLを取り除く:3行
namedepartment_id
鈴木2
高橋2
伊藤3

4. NOT EXISTS:一致する除外候補がない社員を残す

WITH excluded_departments (department_id) AS (
  VALUES (1), (NULL)
)
SELECT e.name, e.department_id
FROM employees AS e
WHERE NOT EXISTS (
  SELECT 1 FROM excluded_departments AS x
  WHERE x.department_id = e.department_id
)
ORDER BY e.id;

NOT EXISTSは内側のSELECTに一致する行がないかを調べます。SELECT 1の1は人数ではなく、行の存在を調べるための定数です。NULL同士も = では一致しないので、部署未設定の田中さんも残ります。上のNOT INとは結果が異なります。

4. NOT EXISTS:一致する除外候補がない社員を残す:4行
namedepartment_id
鈴木2
高橋2
田中NULL
伊藤3

5. NOT EXISTSでも部署未設定の社員は除きたい

WITH excluded_departments (department_id) AS (
  VALUES (1), (NULL)
)
SELECT e.name, e.department_id
FROM employees AS e
WHERE e.department_id IS NOT NULL
  AND NOT EXISTS (
    SELECT 1 FROM excluded_departments AS x
    WHERE x.department_id = e.department_id
  )
ORDER BY e.id;

社員側にもIS NOT NULLを付け、部署未設定は対象外というルールを明示します。どちらが正しいかは目的次第です。NOT EXISTSが常に高速、常にNOT INと同じ結果という意味ではありません。

5. NOT EXISTSでも部署未設定の社員は除きたい:3行
namedepartment_id
鈴木2
高橋2
伊藤3
うまくいかないときに確認するエラーや想定と違う結果が出たときの確認ポイント

うまくいかないとき

NOT INで0件になったら、除外候補を返す内側のSELECTを単独で確認し、NULLが含まれていないか調べます。次に社員側のNULLを残すか決めます。ここでの例は共通サンプル表とSELECT内の仮データだけを使用し、実データを更新しません。

PostgreSQLの構文を基準にしています。MySQL・SQL Server・SQLiteなどでは、一部の構文や挙動が異なります。

公式ドキュメントで詳しく確認する

同じカテゴリの項目

一覧に戻る