SQLのINTERSECTとINTERSECT ALLの違いと実務での活用方法

こんにちは!このページでは、SQLの集合演算の一つ「INTERSECT」について、使用する際の注意点を整理しながら、その仕組みや使い方を紹介します。

試した環境

  • PostgreSQL 17.5

SQLの集合演算とは?

SQLの「集合演算」は、複数の SELECT 文の結果を組み合わせて、新たな結果セットを作成するための便利な機能です。
よく使われる演算子には、 UNIONINTERSECTEXCEPT (Oracleでは MINUS)などがあります。

これらの集合演算は直感的に理解しやすいため、「なんとなくのイメージで使っている」という方も少なくないかもしれません。
しかし、実際の動作がイメージと異なる場合もあり、意図しない結果につながることがあります。

そこで今回は、INTERSECT に焦点を当て、具体的なデータを使いながら、その仕組みや注意点を解説していきます。

INTERSECTとINTERSECT ALL

INTERSECTINTERSECT ALL は、複数の SELECT 文に共通する行を抽出するための集合演算です。
言い換えれば、「両方の結果セットに存在する行のみを取り出す」処理です。

両者の違いは、抽出した共通行の重複をどのように扱うかにあります。
INTERSECT は、重複を取り除き、一意な行のみを返します。一方、INTERSECT ALL は重複を保持したまま、すべての一致する行を返します。

なお、いずれも 使用する SELECT 文同士では、列の数および対応する列のデータ型が一致している必要があります。

INTERSECTのイメージ

「A と B の両方に含まれる共通のデータ」という考え方は、以下のような図で表すことができます。
INTERSECT および INTERSECT ALL のどちらも、基本的なイメージ図は同様です。

intersect (all)AqueryBquery

イメージ図だけでは、INTERSECTINTERSECT ALL の違いが分かりにくいことがあります。
そのため、共通行に対する重複の扱いについて、正しく理解しておくことが重要です。

ここでは、「購入履歴」テーブルに登録されたデータを使って、実際にどのような結果が返ってくるのかを確認してみましょう。

購入履歴データを表示

 顧客名 | 購入年 
--------+--------
 加藤   | 2024
 加藤   | 2024
 高木   | 2024
 志村   | 2024
 仲本   | 2024
 仲本   | 2024
 高木   | 2025
 仲本   | 2025
 内村   | 2025
 仲本   | 2025
 高木   | 2023
 南原   | 2023
 杉本   | 2022

共通する顧客名を抽出する

実際に INTERSECTINTERSECT ALL を使って、2024年と2025年の両方で購入実績のある顧客名を抽出してみます。
この2年間には、2024年に6件、2025年に4件の購入データがあり、合計で10件の購入記録が存在します。
そのうち、2024年と2025年の両方で購入した顧客は2名おり、共通する顧客名のデータ(行)は3件あります。

それでは、INTERSECT を使って実際に実行してみます。

INTERSECTの抽出結果を表示

SELECT customer_name FROM purchase_history where purchase_year = '2024'
INTERSECT
SELECT customer_name FROM purchase_history where purchase_year = '2025'
;
 customer_name 
---------------
 仲本
 高木
(2 rows)

INTERSECT の実行結果として、2名の顧客が返されました。つまり、2024年と2025年に共通する3行のデータから重複を取り除いた、一意な2行が結果として得られたことになります。

次に、INTERSECT ALL を使って実際に実行してみます。

INTERSECT ALLの抽出結果を表示

SELECT customer_name FROM purchase_history where purchase_year = '2024'
INTERSECT ALL
SELECT customer_name FROM purchase_history where purchase_year = '2025'
;
 customer_name 
---------------
 仲本
 仲本
 高木
(3 rows)

INTERSECT ALL の実行結果として、3行の顧客データが返されました。つまり、2024年と2025年の両方に存在する共通の行が、そのままの件数で抽出されたことになります。

対象を追加し顧客名を抽出する

INTERSECTINTERSECT ALL は、複数の SELECT 文の結果を組み合わせて処理できるため、2023年の購入データを加えることも可能です。
たとえば、「2023年・2024年・2025年」のすべてで購入実績のある顧客名を抽出するケースも試してみましょう。
この3年間すべてで購入した顧客は1名で、共通する顧客名の行も1件だけです。

INTERSECTの抽出結果を表示

SELECT customer_name FROM purchase_history where purchase_year = '2024'
INTERSECT
SELECT customer_name FROM purchase_history where purchase_year = '2025'
INTERSECT
SELECT customer_name FROM purchase_history where purchase_year = '2023'
;
 customer_name 
---------------
 高木
(1 row)
INTERSECT ALLの抽出結果を表示

SELECT customer_name FROM purchase_history where purchase_year = '2024'
INTERSECT ALL
SELECT customer_name FROM purchase_history where purchase_year = '2025'
INTERSECT ALL
SELECT customer_name FROM purchase_history where purchase_year = '2023'
;
 customer_name 
---------------
 高木
(1 row)

INTERSECTINTERSECT ALL のいずれの実行結果も、1行の顧客データが返されました。このように、共通する行に重複がない場合は、両者とも同じ結果になります。

実務での活用方法

では、実際の現場ではどのような場面で INTERSECTINTERSECT ALL が活用されているのでしょうか。

私自身がこれらをよく使うのは、本番環境とテスト環境のデータ比較や、システム改修の前後でデータに差異がないかを確認するケースです。
すべてのカラムの値が一致しているかを一括でチェックできるため、差異の有無を効率的かつ確実に把握できます。

現場では、データをExcelに貼り付けて目視や数式で比較する方法もよく見かけますが、このやり方は非効率なうえ、行ズレによって誤判定が発生することも少なくありません。
ケースによっては、INTERSECT を使った比較のほうが、安全かつスマートに処理できるため、選択肢のひとつとして覚えておくと役立ちます。

ただ、システム開発の業務コード内では INTERSECTINTERSECT ALL を使用する機会は、実際にはそれほど多くないかもしれません。
というのも、コード内ですべてのカラムを比較するようなケースは少なく、多くの場合は主キーや一部のキー項目を基準に処理されるためです。
また、パフォーマンスや保守性の観点からも、より柔軟に記述できる EXISTS を使う方が好まれる傾向にあります。
実際、私自身も本番環境のコードで INTERSECT を使用した経験はありません。

それでも、データの検証やリカバリといった一時的な用途では、INTERSECT は非常に有効で、強力な選択肢となります。

📌今回のまとめ

今回は、SQLの集合演算の中から INTERSECTINTERSECT ALL を取り上げ、特に「重複行の扱い」の違いに注目しながら、実際のデータを使ってその動作の違いを確認しました。

どちらの構文も、複数の SELECT 文に共通する行を抽出するためのもので、INTERSECT は重複を除外し、INTERSECT ALL は重複をそのまま保持する点が大きな違いです。

これらは、すべてのカラムの一致を簡潔に確認できるため、一時的なデータ検証やリカバリ対応などの場面で特に有効です。
状況に応じて使いこなすことで、作業の効率化やミスの防止にもつながるため、選択肢のひとつとしてぜひ覚えておきたい構文です。

そのほかの集合演算子はこちらで紹介しています

👉 UNION へ

👉 EXCEPT へ