IN 述語の使い方
shain社員
| name | busho_id |
|---|---|
| 中村 | 2 |
| 伊藤 | 3 |
| 井上 | 7✕ |
| 加藤 | 5✕ |
| … | |
busho_id IN (2, 3)どれかに当てはまった行
| name | busho_id |
|---|---|
| 中村 | 2 |
| 伊藤 | 3 |
| … | |
WHERE busho_id IN (2, 3)
- 取り消し線= 条件に合わないので結果に出てこない行
- 社員 18 行 → どれかに当てはまった行 8 行(10 行が消えます)
18 行のうち残るのは 8 行です。busho_id = 2 OR busho_id = 3 と書いたのとまったく同じ結果になります。
`IN` は「このどれかに当てはまる」を短く書くための述語です。 OR を並べたものと同じ意味になります。ただし否定した NOT IN には、NULL が 1 つ混ざるだけで結果が 0 行になるという有名な落とし穴があります。
この書き方が使えない製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database
未確認: IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01OR を並べる代わりに使う
結論: `列 IN (値1, 値2, …)` は `列 = 値1 OR 列 = 値2 OR …` と同じ意味です。
候補が 2 つなら OR でも大差ありませんが、5 つ 10 つと増えると IN のほうが圧倒的に読みやすくなります。列名を何度も書かずに済むので、列名を打ち間違える事故も減ります。
値は数でも文字列でも構いません。並べる値は同じ種類にしてください。
候補が 1 つだけのときは = で十分ですが、IN で書いても間違いではありません(あとから候補を足しやすい形になります)。
SELECT name, busho_idどの列を出すかFROM shainどの表を見るかWHERE busho_id IN (2, 3)この並びのどれかに一致する行を残すORDER BY shain_id並び順
IN の右側は「値の並び」でも「副問い合わせ」でも構いません。どちらも「この集合に含まれるか」を聞いています。
SELECT name, busho_id
FROM shain
WHERE busho_id IN (2, 3)
ORDER BY shain_id;| name | busho_id |
|---|---|
| 佐藤 | 2 |
| 田中 | 2 |
| 中村 | 2 |
| 小林 | 2 |
| 山田 | 3 |
| 高橋 | 3 |
| 伊藤 | 3 |
| 松本 | 3 |
(8 行)
SELECT name, busho_id
FROM shain
WHERE busho_id = 2 OR busho_id = 3
ORDER BY shain_id;| name | busho_id |
|---|---|
| 佐藤 | 2 |
| 田中 | 2 |
| 中村 | 2 |
| 小林 | 2 |
| 山田 | 3 |
| 高橋 | 3 |
| 伊藤 | 3 |
| 松本 | 3 |
(8 行)
同じ 8 行です。どちらで書いても結果は変わりません。読みやすさで選んでください。
SELECT busho_id, busho_name
FROM busho
WHERE busho_name IN ('開発', '営業')
ORDER BY busho_id;| busho_id | busho_name |
|---|---|
| 2 | 開発 |
| 3 | 営業 |
(2 行)
02右側に副問い合わせを書ける
結論: `IN` の右側には、1 列だけを返す `SELECT` をそのまま置けます。
値を手で並べる代わりに「別の表から取ってきた集合」を渡せます。候補が実行時にしか分からないときは、こちらが基本形になります。
条件は 1 つだけ、副問い合わせが返す列は 1 列であることです。複数列を返すとエラーになります。
値の並びと副問い合わせでは、対応している製品の範囲が少し違います。使えない製品がある例には自動で注記が出ます。
SELECT name
FROM shain
WHERE busho_id IN (SELECT busho_id
FROM busho
WHERE parent_busho_id = 1)
ORDER BY shain_id;| name |
|---|
| 佐藤 |
| 田中 |
| 中村 |
| 小林 |
| 山田 |
| 高橋 |
| 伊藤 |
| 松本 |
(11 行 … うち先頭 8 行を表示)
11 行返ります。部署表から親が経営(busho_id = 1)である部署の番号を集めて、その集合に含まれる社員を出しています。部署が増減しても SQL を書き換える必要がありません。
03⚠️ よくある間違い:NOT IN は NULL 1 つで 0 行になる
結論: `NOT IN` の右側に NULL が 1 つでも混ざると、結果は必ず 0 行になります。
理由は展開すると分かります。x NOT IN (a, b, NULL) は次と同じ意味です。
x <> a AND x <> b AND x <> NULL
最後の x <> NULL は、x が何であっても unknown です。AND は 1 つでも unknown が混ざると true になれない(false か unknown にしかならない)ので、どの行も残りません。
危ないのは副問い合わせを渡したときです。その列に NULL が入っていることに気づかないまま NOT IN を書くと、エラーも警告も出ずに 0 行が返ります。「該当なし」という正しそうに見える嘘の答えが返るのが最悪の点です。
対処は `NOT EXISTS` を使うことです。 NOT EXISTS は「一致する行が 1 つも無いか」を聞くだけなので、NULL の影響を受けません。
SELECT busho_name
FROM busho
WHERE busho_id NOT IN (SELECT busho_id FROM shain);| busho_name |
|---|
(0 行)
実際には法務が該当するのに、0 行が返ります。shain.busho_id には所属未設定の社員 2 人ぶんの NULL が入っているためです。
SELECT busho_name
FROM busho b
WHERE NOT EXISTS (SELECT 1
FROM shain s
WHERE s.busho_id = b.busho_id);| busho_name |
|---|
| 法務 |
(1 行)
法務が 1 行返ります。同じことを聞いているのに結果が違うのは、NULL の扱いが違うからです。**否定するときは NOT EXISTS を既定にしてください。**
04⚠️ よくある間違い:値の並びでも同じことが起きる
結論: 手で並べた値に NULL を書いても同じです。 そして IN(否定なし)のほうにも別の注意があります。
busho_id IN (2, NULL)… NULL に一致する行は無いので、実質IN (2)と同じ結果になります。NULL の行が出てくることはありませんbusho_id NOT IN (2, NULL)… 0 行になります
否定していない IN にも注意が要ります。列そのものが NULL の行は、並びに何を書いても一致しません。 「所属が未設定の社員」を IN の並びで取り出すことはできないので、IS NULL を別に足してください。
SELECT name, busho_id
FROM shain
WHERE busho_id NOT IN (2, 3)
ORDER BY shain_id;| name | busho_id |
|---|---|
| 鈴木 | 1 |
| 加藤 | 5 |
| 吉田 | 5 |
| 井上 | 7 |
| 木村 | 7 |
| 清水 | 4 |
| 斎藤 | 4 |
| 山本 | 4 |
(8 行)
8 行です。所属が 2 でも 3 でもない社員は本来 10 人いますが、渡辺と大野(所属未設定)が落ちています。
SELECT name, busho_id
FROM shain
WHERE busho_id NOT IN (2, 3)
OR busho_id IS NULL
ORDER BY shain_id;| name | busho_id |
|---|---|
| 鈴木 | 1 |
| 加藤 | 5 |
| 吉田 | 5 |
| 井上 | 7 |
| 木村 | 7 |
| 清水 | 4 |
| 斎藤 | 4 |
| 山本 | 4 |
| 渡辺 | NULL |
| 大野 | NULL |
(10 行)
10 行になりました。増えた 2 行が所属未設定の社員です。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- IN / EXISTS(練習問題)IN と EXISTS の使い分けを、もう少し踏み込んで扱います。
- AND / OR / NOTNOT IN が 0 行になる理由は AND と unknown の規則そのものです。
- IS NULLNULL の行を取り出すには IS NULL が要ります。
- BETWEEN 述語「範囲のどこか」を聞くときはこちらを使います。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 副問い合わせ式(IN / NOT IN)一次情報・確認 2026-08-03
- PostgreSQL 18 マニュアル: 比較関数と演算子(IN と NULL)一次情報・確認 2026-08-03
- MySQL 8.4 リファレンスマニュアル: 比較関数と演算子(IN)一次情報・確認 2026-08-03