複数のテーブルに散らばったデータを一つのリストにまとめたい、あるいは2つのデータセットを比較して「共通するデータ」や「差分」だけを抽出したいと考えたことはありませんか?
Oracle SQLの集合演算子(UNION ALL、UNION、INTERSECT、MINUS)を使えば、複数のSELECT文の結果を縦方向に結合したり、数学的な集合論に基づいてデータを抽出したりすることができます。
この記事では、Oracle Database 19cを対象に、これら4つの演算子の違いと具体的な使い分け、パフォーマンスへの影響、そして実務で役立つ注意点を解説します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
結論・要約(やることリスト)
集合演算子を使うと、複数のクエリ結果を1つの結果セットとして扱えます。用途に合わせて以下のように使い分けます。
- すべて結合したい(最速):
UNION ALL- 重複を削除せず、単純に結果をつなげます。ソートが発生しないため高速です。
- 重複なしで結合したい:
UNION- 結果をまとめた後、重複行を削除します(内部でソートまたはハッシュ処理が発生)。
- 共通データを知りたい:
INTERSECT- 両方の結果セットに存在する行(積集合)のみを返します。
- 差分を知りたい:
MINUS- 1つ目の結果セットにあって、2つ目にない行(差集合)を返します。
1. 集合演算子の基礎とルール
具体的なコードを実行する前に、すべての集合演算子に共通する重要なルールを押さえておきましょう。これらを守らないとエラーになります。
- 列の数が同じであること: 結合するすべてのSELECT文で、選択する列数が一致している必要があります。
- データ型が対応していること: 1列目は1列目同士、2列目は2列目同士で、データ型が互換性を持っている必要があります(例: 数値型と数値型)。
- ORDER BYは最後に: 並び替えを行いたい場合、
ORDER BY句は一番最後のSELECT文の後ろに1つだけ記述します。 - NULLの扱い: 集合演算子では、
NULL同士は「等しい値」として扱われます(通常の比較演算子とは挙動が異なります)。
検証用データの作成
本記事のすべての例で使用するサンプルテーブル(table_a, table_b)を作成します。
※SQL内にはマルチバイト文字(日本語など)を含めず、英数字のみを使用しています。
-- 1. 既存テーブルがある場合は削除(エラー無視)
-- DROP TABLE table_a PURGE;
-- DROP TABLE table_b PURGE;
-- 2. 表A (従業員データ想定) の作成
CREATE TABLE table_a (
id NUMBER PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
value NUMBER NOT NULL
);
-- 3. 表B (プロジェクトメンバーデータ想定) の作成
CREATE TABLE table_b (
id NUMBER PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
value NUMBER NOT NULL
);
-- 4. table_aにデータを挿入
-- Alice: Aのみ, Bob: 共通(値も同じ), Charlie: ID/名前は同じだが値が違う
INSERT INTO table_a (id, name, value) VALUES (1, 'Alice', 100);
INSERT INTO table_a (id, name, value) VALUES (2, 'Bob', 200);
INSERT INTO table_a (id, name, value) VALUES (3, 'Charlie', 300);
-- 5. table_bにデータを挿入
-- Bob: 共通, Charlie: 値違い, David: Bのみ
INSERT INTO table_b (id, name, value) VALUES (2, 'Bob', 200);
INSERT INTO table_b (id, name, value) VALUES (3, 'Charlie', 400);
INSERT INTO table_b (id, name, value) VALUES (4, 'David', 500);
-- 6. コミット
COMMIT;
SQL> SELECT * FROM table_a;
ID NAME VALUE
---------- -------------------- ----------
1 Alice 100
2 Bob 200
3 Charlie 300
SQL> SELECT * FROM table_b;
ID NAME VALUE
---------- -------------------- ----------
2 Bob 200
3 Charlie 400
4 David 500
2. UNION ALL:すべての結果を結合
UNION ALLは、複数のクエリ結果をそのまま連結して表示します。重複があっても削除しません。
特徴
- パフォーマンス: 重複チェックを行わないため、4つの演算子の中で最も高速です。
- 用途: ログデータの統合や、重複があり得ない(または重複しても良い)データの単純結合。
実行例
SELECT id, name, value FROM table_a
UNION ALL
SELECT id, name, value FROM table_b;
実行結果と解説:
SQL> SELECT id, name, value FROM table_a
2 UNION ALL
3 SELECT id, name, value FROM table_b;
ID NAME VALUE
---------- -------------------- ----------
1 Alice 100
2 Bob 200
3 Charlie 300
2 Bob 200
3 Charlie 400
4 David 500
6 rows selected.
ID | NAME | VALUE
---|---------|------
1 | Alice | 100
2 | Bob | 200
3 | Charlie | 300
2 | Bob | 200 <-- Bobが重複して表示される
3 | Charlie | 400
4 | David | 500
表Aの3行と表Bの3行、合計6行がそのまま出力されます。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
3. UNION:重複を除外して結合
UNIONは、結果を結合した後に重複行を削除します。
特徴
- パフォーマンス: 重複を排除するために内部でソート(またはハッシュ処理)が行われるため、
UNION ALLよりもコストがかかります。 - 注意点: 「行全体」が完全に一致する場合のみ重複とみなされます。一部の列が異なれば別データとして残ります。
実行例
SELECT id, name, value FROM table_a
UNION
SELECT id, name, value FROM table_b;
実行結果と解説:
SQL> SELECT id, name, value FROM table_a
2 UNION
3 SELECT id, name, value FROM table_b;
ID NAME VALUE
---------- -------------------- ----------
1 Alice 100
2 Bob 200
3 Charlie 300
3 Charlie 400
4 David 500
ID | NAME | VALUE
---|---------|------
1 | Alice | 100
2 | Bob | 200 <-- 重複していたBobは1行にまとめられた
3 | Charlie | 300 <-- 値が異なるため残る
3 | Charlie | 400 <-- 値が異なるため残る
4 | David | 500
Bob(ID:2)はすべての列が一致するため1行になりました。一方、Charlie(ID:3)は value 列の値(300と400)が異なるため、重複とはみなされず両方表示されます。
4. INTERSECT:共通部分(積集合)の抽出
INTERSECTは、両方のクエリ結果に共通して存在する行のみを返します。
用途
- 2つの異なるシステム間で整合性が取れているデータの確認。
- 「条件Aを満たし、かつ条件Bも満たす」データの抽出(AND条件に近いイメージ)。
実行例
SELECT id, name, value FROM table_a
INTERSECT
SELECT id, name, value FROM table_b;
実行結果と解説:
SQL> SELECT id, name, value FROM table_a
2 INTERSECT
3 SELECT id, name, value FROM table_b;
ID NAME VALUE
---------- -------------------- ----------
2 Bob 200
完全に一致している Bob の行だけが出力されます。Charlie は値が異なるため「共通データ」とはみなされません。
5. MINUS:差分(差集合)の抽出
MINUSは、1つ目のクエリ結果から、2つ目のクエリ結果にある行を引き算して残った行を返します。
用途
- 「AにはあるがBにはない」データの特定(例:マスタに登録されているが売上がない商品)。
- データ移行前後の差異チェック。
実行例
SELECT id, name, value FROM table_a
MINUS
SELECT id, name, value FROM table_b;
実行結果と解説:
SQL> SELECT id, name, value FROM table_a
2 MINUS
3 SELECT id, name, value FROM table_b;
ID NAME VALUE
---------- -------------------- ----------
1 Alice 100
3 Charlie 300
表Aから表Bの内容を引きます。
Alice: 表Bにいないので残る。Bob: 表Bにもいるので消える。Charlie: IDは同じだが行全体(Value)が一致しないため、表Bにあるデータとは別物とみなされ、表A側のデータが残る。
注意:
MINUSは記述する順序が重要です。table_b MINUS table_aと書くと結果は逆(DavidとCharlie(400))になります。
6. トラブルシューティング(よくあるエラー)
集合演算子を使用する際によく遭遇するエラーとその対処法です。
| エラーコード | エラーメッセージ | 原因と対処法 |
| ORA-01790 | 対応する式には同じデータ型を指定する必要があります | 原因: 1つ目のSELECTのn列目と、2つ目のSELECTのn列目の型が合っていません(例:数値と文字列)。 対処: TO_CHAR や TO_NUMBER 関数を使って型を合わせるか、NULLプレースホルダ(NULL AS col_name)を使って型を揃えます。 |
| ORA-01789 | 問合せブロックのSELECTリストの数が正しくありません | 原因: 結合するSELECT文同士で列の数が違います。 対処: 列数を合わせます。足りない列には NULL や固定値を入れて数合わせをします。 |
7. 運用・実装上の注意点
メリットとデメリット
- メリット: 複雑な条件(
WHERE句のORやANDの組み合わせ)で書くと読みにくくなるクエリを、シンプルに分割して記述できます。 - デメリット: 特に
UNION、INTERSECT、MINUSは内部で全件ソートやハッシュ結合を行うことが多く、大量データを扱う場合はパフォーマンスに注意が必要です。可能であればUNION ALLを優先して使用しましょう。
パフォーマンス改善のヒント
重複データが存在しないことが分かっている場合、あるいは重複しても問題ない場合は、必ず UNION ALL を使用してください。不要な重複排除処理(ソート)をスキップできるため、応答速度が劇的に向上することがあります。
8. FAQ:よくある質問
Q: ORDER BY句はどこに書けばいいですか?
A: 一番最後のSELECT文の後ろに記述します。途中のSELECT文に書くとエラーになります。列指定は、最初のSELECT文の列名または列番号を使用します。
Q: INTERSECTやMINUSで重複行はどう扱われますか?
A: 基本的に重複は排除されて一意な行として返されます(DISTINCT がかかったような状態になります)。
Q: 3つ以上のテーブルを結合できますか?
A: はい、可能です。SELECT … UNION ALL SELECT … UNION ALL SELECT … のように連続して記述できます。上から順に評価されます。
まとめ
Oracle SQLの集合演算子を使いこなすと、データの統合や比較が非常に楽になります。
- UNION ALL: 重複込みで結合(最速・基本はこれ)。
- UNION: 重複を除外して結合(コスト高)。
- INTERSECT: 共通する行のみ抽出。
- MINUS: 差分を抽出(A – B)。
- ルール: 列数と型を合わせる。ソートは最後に。
まずは UNION ALL でデータを繋げることから始め、要件に応じて MINUS での差分チェックなどを試してみてください。
本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。
[参考]
Oracle Database SQL言語リファレンス 19c
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?




コメント