集合演算

集合演算

🌍 実世界のアナロジー

2つの名刺の束を持っていると想像してください:

集合演算は、2つのクエリ結果セットに対して「結合、積集合、差集合」の演算を実行します。


🎯 コアコンセプト

UNION — 重複除去付き結合

2つの結果セットを結合し、重複する行を自動的に除去します。

SQL
SELECT city FROM employees
UNION
SELECT city FROM departments;

UNION ALL — 重複除去なし結合

2つの結果セットを結合し、すべての重複行を保持します。重複除去が不要なため、パフォーマンスが向上 します。

SQL
SELECT city FROM employees
UNION ALL
SELECT city FROM departments;

INTERSECT — 積集合

両方の 結果セットに 存在する行 を返します。

SQL
SELECT city FROM employees
INTERSECT
SELECT city FROM departments;

EXCEPT / MINUS — 差集合

最初の結果セットに存在するが、2番目には 存在しない行 を返します。

SQL
-- EXCEPT(SQL Server、PostgreSQL)
SELECT city FROM employees
EXCEPT
SELECT city FROM departments;

-- MINUS(Oracle)
SELECT city FROM employees
MINUS
SELECT city FROM departments;

カラムマッチングルール

集合演算を使用する際、2つの SELECT 文は以下を満たす必要があります:

ルール 説明
カラム数が同じ 両方のSELECTは同じ数のカラムを持つ必要がある
型が互換性がある 対応するカラムは互換性のあるデータ型を持つ必要がある
ORDER BYは最後に 文の最後に1回だけ使用可能
SQL
-- 正しい:2つのカラム、型が一致
SELECT first_name, salary FROM employees
UNION
SELECT department_name, budget FROM departments;

-- 間違い:カラム数が異なる
SELECT first_name, salary FROM employees
UNION
SELECT department_name;  -- ❌ カラム数が不一致

💡 どの演算をいつ使用するか

演算 シナリオ 重複除去 パフォーマンス
UNION 結合して重複除去が必要 ✅ あり 遅い
UNION ALL 重複除去なしで結合 ❌ なし 速い
INTERSECT 共通部分を検索 ✅ あり 中程度
EXCEPT 差分を検索 ✅ あり 中程度
💡 経験則: 重複がないことが確実な場合は、パフォーマンス向上のため UNION ALL を優先してください。


📝 基本構文

SQL
-- UNION構文
SELECT カラム1, カラム2 FROM テーブル1
UNION
SELECT カラム1, カラム2 FROM テーブル2
[ORDER BY カラム1];

-- UNION ALL構文
SELECT カラム1, カラム2 FROM テーブル1
UNION ALL
SELECT カラム1, カラム2 FROM テーブル2;

-- INTERSECT構文
SELECT カラム1, カラム2 FROM テーブル1
INTERSECT
SELECT カラム1, カラム2 FROM テーブル2;

-- EXCEPT構文
SELECT カラム1, カラム2 FROM テーブル1
EXCEPT
SELECT カラム1, カラム2 FROM テーブル2;
💡 ヒント:

  • 集合演算では、カラム名は最初のSELECTによって決定されます
  • ORDER BYは最後にのみ出現でき、通常はカラムの序数を使用します
  • 各SELECTには独自のWHERE、GROUP BYを含めることができます

📌 例題

例:すべての名前のソースをクエリ

社員名と部門名を1つの結果セットに結合します。

SQL
-- すべての「名前」ソースを表示:社員 + 部門マネージャー
SELECT first_name AS name, '社員' AS source
FROM employees
UNION ALL
SELECT department_name, '部門'
FROM departments
ORDER BY source;
▶ 試してみよう

説明:データソースを区別するために、定数列を追加しています。

例:社員がいるが部門がない都市を検索

SQL
-- 社員がいる都市から部門がある都市を引く
SELECT city FROM employees
EXCEPT
SELECT city FROM departments;
▶ 試してみよう

アプローチEXCEPT を差集合演算として使用し、「社員テーブルにのみ出現する都市」を迅速に検索します。


🎬 シナリオ詳細

シナリオ1:マルチチャネル顧客リストの結合

オンラインとオフラインの顧客テーブルを結合・重複除去し、完全な顧客ディレクトリを作成します。

SQL
-- オンライン顧客
SELECT customer_name, email, 'オンライン' AS channel
FROM online_customers
UNION
-- オフライン顧客
SELECT customer_name, email, 'オフライン'
FROM offline_customers
ORDER BY customer_name;

ポイント:重複する顧客を自動的に除去するために、UNION ALL ではなく UNION を使用します。

シナリオ2:2か月間の売上差異を比較

今月は売上があったが先月はなかった商品を検索します。

SQL
-- 今月売れた商品
SELECT product_id FROM orders
WHERE order_date >= '2026-06-01'
EXCEPT
-- 先月売れた商品
SELECT product_id FROM orders
WHERE order_date >= '2026-05-01'
  AND order_date < '2026-06-01';

ポイントEXCEPT は「差分を検索」シナリオに天然適しています。


❓ よくある質問

質問:UNIONとUNION ALLのどちらをいつ使用すべきですか? 回答: 重複除去が不要な場合は、余分な重複除去ステップが不要でパフォーマンスが良いため、UNION ALL を優先してください。重複除去が特に必要な場合のみ UNION を使用してください。

質問:集合演算でカラム名が一致しない場合はエラーになりますか? 回答: いいえ、結果セットのカラム名は最初の SELECT によって決定されます。ただし、カラム数と対応するカラムのデータ型は一致する必要があります。

質問:INTERSECTとJOINの違いは何ですか? 回答: INTERSECT は行全体を照合して積集合を求めますが、JOIN は指定された条件に基づいてテーブルを関連付けます。「同じ行を検索」する必要がある場合は INTERSECT を使用し、「異なるテーブルのカラムをフィールドで関連付ける」必要がある場合は JOIN を使用してください。

質問:MySQLはINTERSECTとEXCEPTをサポートしていますか? 回答: MySQL 8.0以降は INTERSECTEXCEPT をサポートしています。以前のバージョンでは、INNER JOINNOT EXISTS / LEFT JOIN ... IS NULL を使用してシミュレートする必要があります。


📖 まとめ

演算 目的 重複除去
UNION 2つの結果セットを結合
UNION ALL 2つの結果セットを結合(重複を保持)
INTERSECT 2つの結果セットの積集合
EXCEPT 2つの結果セットの差集合

📝 演習

  1. UNION を使用して、employees テーブルから給与が8000を超える社員と、departments テーブルから予算が100000を超える部門名を結合してください。
  2. INTERSECT を使用して、employees テーブルと departments テーブルの両方に存在する都市を検索してください。
  3. EXCEPT を使用して、部門があるが社員が割り当てられていない都市を検索してください。
  4. 考えてみましょう:集合演算で2つのクエリ結果のカラム型が完全に一致しない場合(例:INTとVARCHAR)、どうなりますか?

次のレッスン

次は 制約とキー を学びます。PRIMARY KEY、FOREIGN KEY、その他の制約を使用してデータ整合性を確保する方法を理解します。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%