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;
構文一覧
| 構文 | 概要 |
|---|---|
| INTERSECT | 2つのSELECT結果の共通行を返します。重複は除去されます。 |
| EXCEPT | 左のSELECT結果から右のSELECT結果に含まれる行を除いた差分行を返します(PostgreSQL・SQLiteなど)。 |
| MINUS | EXCEPT と同義です(Oracle・DB2で使用)。 |
サンプルコード
以下の『orders』テーブルを例に説明します。
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』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。