「AテーブルにはあるけどBテーブルには存在しないデータを取りたい」──そんな場面はSQL開発でよくあります。この記事では、片方のテーブルにしか存在しないデータを抽出する代表的な3つの方法を、具体的なサンプルデータと一緒にわかりやすく解説します。
サンプルデータ
以下のテーブルを例に使います。
テーブルA(受注テーブル)
order_id | customer_id ---------|------------ 1 | 101 2 | 102 3 | 103 4 | 104
テーブルB(請求済みテーブル)
order_id | customer_id ---------|------------ 1 | 101 3 | 103
→ AにあってBに存在しない(=未請求の)注文:order_id 2 と 4 を抽出したい。
方法① LEFT JOIN(外部結合)+ IS NULL
最も広く使われる方法です。LEFT JOINでBテーブルを結合し、Bに値がない(NULL)行だけをWHEREで絞り込みます。
SELECT
A.*
FROM
テーブルA AS A
LEFT JOIN テーブルB AS B
ON A.order_id = B.order_id
WHERE
B.order_id IS NULL;
結果:
order_id | customer_id ---------|------------ 2 | 102 4 | 104
ポイント:LEFT JOINはAの全行を残し、Bに一致する行がなければNULLを返します。WHERE B.キー IS NULL とすることで「Bに存在しない行のみ」を取り出せます。MySQL・PostgreSQL・SQLiteなど、ほぼすべてのDBで使えます。
方法② NOT EXISTS
サブクエリを使う方法です。「Bテーブルに一致する行が存在しないAの行」を取り出します。
SELECT
A.*
FROM
テーブルA AS A
WHERE
NOT EXISTS (
SELECT 1
FROM テーブルB AS B
WHERE A.order_id = B.order_id
);
ポイント:NOT EXISTSはサブクエリが1件でも一致したらFALSE、0件ならTRUEを返します。SELECT *よりSELECT 1を使うのが一般的(処理を軽くするため)。NULL値が含まれる場合も安全に動作するのが利点です。
方法③ EXCEPT(差集合)
集合演算子のEXCEPTを使う方法です。「AのSELECT結果からBのSELECT結果を引く」イメージです。
SELECT order_id FROM テーブルA EXCEPT SELECT order_id FROM テーブルB;
ポイント:シンプルに書けますが、MYSQLは8.0.31以降でサポート(それ以前は使えません)。PostgreSQL・SQL Serverでは標準的に使えます。OracleはEXCEPTではなくMINUSという名前になります。
3つの方法の比較まとめ
| 方法 | 書きやすさ | パフォーマンス | NULL対応 | 対応DB |
|---|---|---|---|---|
| LEFT JOIN + IS NULL | ○ | インデックスがあれば高速 | △(NULLに注意) | 全DB |
| NOT EXISTS | ○ | インデックスがあれば高速 | ◎(安全) | 全DB |
| EXCEPT / MINUS | ◎(シンプル) | 場合による | ○ | DB依存 |
どれを使えばいいか?
迷ったときは以下を参考にしてください。
- 汎用性重視なら → LEFT JOIN + IS NULL(どのDBでも動く)
- NULL値が含まれて不安なら → NOT EXISTS(最も安全)
- シンプルに書きたいなら → EXCEPT / MINUS(DBが対応していれば)
パフォーマンス面では、結合キーにインデックスが貼られていれば LEFT JOIN も NOT EXISTS もほぼ同等の速度です。大量データの場合は実行計画(EXPLAIN)を確認して選ぶのがおすすめです。
よくある間違いとハマりポイント
- NOT INはNULLに弱い:
WHERE A.id NOT IN (SELECT id FROM B)はBにNULLが1件でもあると結果が空になります。NOT EXISTSかLEFT JOINを使いましょう。 - 結合キーの型が違うと動かない:数値型と文字列型で結合しようとしてもマッチしないことがあります。
- 複合キーの場合:複数カラムで一致を見る場合はON句を複数条件にしてください。
まとめ
片方のテーブルにしか存在しないデータを抽出する方法は3つあります。
- LEFT JOIN + IS NULL:汎用的で使いやすい定番手法
- NOT EXISTS:NULL値にも安全で信頼性が高い
- EXCEPT / MINUS:シンプルだがDBの対応を確認が必要
用途やDB環境に応じて使い分けてみてください。

