Oracle SQL 集合演算子:UNION ALLとMINUS等の使い方

Oracle Master Silver

複数のテーブルに散らばったデータを一つのリストにまとめたい、あるいは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 と書くと結果は逆(DavidCharlie(400))になります。


6. トラブルシューティング(よくあるエラー)

集合演算子を使用する際によく遭遇するエラーとその対処法です。

エラーコードエラーメッセージ原因と対処法
ORA-01790対応する式には同じデータ型を指定する必要があります原因: 1つ目のSELECTのn列目と、2つ目のSELECTのn列目の型が合っていません(例:数値と文字列)。
対処: TO_CHARTO_NUMBER 関数を使って型を合わせるか、NULLプレースホルダ(NULL AS col_name)を使って型を揃えます。
ORA-01789問合せブロックのSELECTリストの数が正しくありません原因: 結合するSELECT文同士で列の数が違います。
対処: 列数を合わせます。足りない列には NULL や固定値を入れて数合わせをします。

7. 運用・実装上の注意点

メリットとデメリット

  • メリット: 複雑な条件(WHERE句のORANDの組み合わせ)で書くと読みにくくなるクエリを、シンプルに分割して記述できます。
  • デメリット: 特に UNIONINTERSECTMINUS は内部で全件ソートやハッシュ結合を行うことが多く、大量データを扱う場合はパフォーマンスに注意が必要です。可能であれば 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の集合演算子を使いこなすと、データの統合や比較が非常に楽になります。

  1. UNION ALL: 重複込みで結合(最速・基本はこれ)。
  2. UNION: 重複を除外して結合(コスト高)。
  3. INTERSECT: 共通する行のみ抽出。
  4. MINUS: 差分を抽出(A – B)。
  5. ルール: 列数と型を合わせる。ソートは最後に。

まずは UNION ALL でデータを繋げることから始め、要件に応じて MINUS での差分チェックなどを試してみてください。

本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。


[参考]
Oracle Database SQL言語リファレンス 19c

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?

コメント

タイトルとURLをコピーしました