言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

  1. トップページ
  2. SQL辞典
  3. INTERSECT / EXCEPT

INTERSECT / EXCEPT

対応: SQL-92(1992)

2つのSELECT結果の共通行(INTERSECT)や差分行(EXCEPT / MINUS)を取り出す集合演算子です。どちらも重複行は除去されます。

構文

INTERSECT: 両方のSELECTに共通する行を返します。

SELECT col FROM table_a
INTERSECT
SELECT col FROM table_b;

EXCEPT: 左のSELECTにあって右にない行を返します(SQL標準)。

SELECT col FROM table_a
EXCEPT
SELECT col FROM table_b;

MINUS: EXCEPT と同義です(Oracle では MINUS を使います)。

SELECT col FROM table_a
MINUS
SELECT col FROM table_b;

構文一覧

構文概要
INTERSECT2つのSELECT結果の共通行を返します。重複は除去されます。
EXCEPT左のSELECT結果から右のSELECT結果に含まれる行を除いた差分行を返します(PostgreSQL・SQLiteなど)。
MINUSEXCEPT と同義です(Oracle・DB2で使用)。

サンプルコード

以下の『orders』テーブルを例に説明します。

orders order_id customer_id order_date 1 1001 2025-01-10 2 1003 2025-01-15 3 1005 2025-01-22 4 1001 2025-02-05 5 1005 2025-02-18 5 rows in set

1月と2月の両方に注文した顧客IDを取得します(INTERSECT)。『MONTH』は日付から月を取り出す関数です。

sample_intersect_except.sql
SELECT customer_id
FROM orders
WHERE MONTH(order_date) = 1
INTERSECT
SELECT customer_id
FROM orders
WHERE MONTH(order_date) = 2;
+-------------+
| customer_id |
+-------------+
|        1001 |
|        1005 |
+-------------+
2 rows in set

1月に注文したが2月には注文しなかった顧客を取得します(EXCEPT)。

sample_intersect_except.sql
SELECT customer_id
FROM orders
WHERE MONTH(order_date) = 1
EXCEPT
SELECT customer_id
FROM orders
WHERE MONTH(order_date) = 2;
+-------------+
| customer_id |
+-------------+
|        1003 |
+-------------+
1 row in set

MySQL は INTERSECT / EXCEPT が使えないため IN / NOT IN で代替します。

sample_intersect_except.sql
-- INTERSECT の代替。
SELECT DISTINCT customer_id FROM orders WHERE MONTH(order_date) = 1
  AND customer_id IN (SELECT customer_id FROM orders WHERE MONTH(order_date) = 2);

-- EXCEPT の代替。
SELECT DISTINCT customer_id FROM orders WHERE MONTH(order_date) = 1
  AND customer_id NOT IN (SELECT customer_id FROM orders WHERE MONTH(order_date) = 2);
-- INTERSECT の代替
+-------------+
| customer_id |
+-------------+
|        1001 |
|        1005 |
+-------------+
2 rows in set

-- EXCEPT の代替
+-------------+
| customer_id |
+-------------+
|        1003 |
+-------------+
1 row in set

データベース別の書き方

PostgreSQL・SQLite は『INTERSECT』・『EXCEPT』をそのまま使用できます。

SELECT customer_id FROM orders WHERE MONTH(order_date) = 1
INTERSECT
SELECT customer_id FROM orders WHERE MONTH(order_date) = 2;

Oracle では『EXCEPT』の代わりに『MINUS』を使用します。『INTERSECT』は同じ構文で使えます。

SELECT customer_id FROM orders WHERE EXTRACT(MONTH FROM order_date) = 1
MINUS
SELECT customer_id FROM orders WHERE EXTRACT(MONTH FROM order_date) = 2;

MySQL は 8.0.31 以降で『INTERSECT』・『EXCEPT』をサポートしています。それ以前のバージョンでは『IN』・『NOT IN』で代替してください。

-- MySQL(8.0.31 未満)での INTERSECT 代替
SELECT DISTINCT customer_id FROM orders WHERE MONTH(order_date) = 1
  AND customer_id IN (SELECT customer_id FROM orders WHERE MONTH(order_date) = 2);

-- MySQL(8.0.31 未満)での EXCEPT 代替
SELECT DISTINCT customer_id FROM orders WHERE MONTH(order_date) = 1
  AND customer_id NOT IN (SELECT customer_id FROM orders WHERE MONTH(order_date) = 2);

概要

『INTERSECT』と『EXCEPT』はSQLの集合演算子で、重複行は自動的に除去されます(UNION と同じ挙動)。列数とデータ型の互換性は UNION と同様に必要です。

MySQLは8.0.31以降でINTERSECT・EXCEPTをサポートしています。それ以前のバージョンでは IN・NOT IN・EXISTS・NOT EXISTS を使って代替してください。Oracleでは EXCEPT の代わりに MINUS を使います。

集合演算子の仲間である UNION・UNION ALL の使い方は『UNION / UNION ALL』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。