【SQL】UNION・UNION ALLで結果セットを結合する

SQL

こんにちは、かつコーチです。

「今月の注文テーブル」と「過去の注文アーカイブテーブル」を1つのリストとしてまとめて表示したい。
こうした「複数のSELECT結果を縦に連結したい」場面で使うのがUNION・UNION ALLです。

これまで解説してきたJOINが「テーブルを横につなげる」ものだとすると、UNIONは「結果セットを縦につなげる」ものだとイメージすると理解しやすくなります。
この記事では、orders_2025・orders_2026という2つのテーブルを例に使い方を解説します。

UNION・UNION ALLとは?

複数のSELECT結果を縦に連結する構文

UNIONとは、複数のSELECT文の結果を、縦に連結して1つの結果セットにまとめる構文です。
JOINが「カラムを横に増やす」のに対し、UNIONは「行を縦に増やす」という違いがあります。

CREATE TABLE orders_2025 (
    id INT PRIMARY KEY,
    customer_name VARCHAR(50),
    amount INT
);

CREATE TABLE orders_2026 (
    id INT PRIMARY KEY,
    customer_name VARCHAR(50),
    amount INT
);

UNIONとUNION ALLの違い

UNIONとUNION ALLは、どちらも複数のSELECT結果を連結する点は同じですが、重複行の扱いが異なります。

  • UNION:連結した結果から重複する行を自動的に除去する
  • UNION ALL:連結した結果をそのまま全件残す(重複除去をしない)

この違いが、パフォーマンスと結果の正確さの両方に影響するため、次の「基本の書き方」で具体的に見ていきます。

基本の書き方

手順1:UNIONで重複を除いて結合する

SELECT customer_name FROM orders_2025
UNION
SELECT customer_name FROM orders_2026;

2025年と2026年の両方に注文がある顧客がいた場合でも、UNIONを使うとその顧客名は結果に1回しか表示されません。
「2025年・2026年を通じて注文実績がある顧客の一覧(重複なし)」を求めたいときに適しています。

手順2:UNION ALLで全件を結合する

SELECT customer_name FROM orders_2025
UNION ALL
SELECT customer_name FROM orders_2026;

UNION ALLでは、2025年と2026年の両方に注文がある顧客の名前が、そのまま2回表示されます。
「単純に全件を連結したい」「そもそも重複が発生しない、または重複していても問題ない」場合は、こちらを使います。

手順3:3つ以上のSELECT文を連結する

UNION・UNION ALLは3つ以上のSELECT文をつなげることもできます。

SELECT customer_name, 2024 AS order_year FROM orders_2024
UNION ALL
SELECT customer_name, 2025 AS order_year FROM orders_2025
UNION ALL
SELECT customer_name, 2026 AS order_year FROM orders_2026;

このように、年度ごとに分かれたテーブルへ「どの年のデータか」を示す列を追加しながら連結すると、後から年度別に絞り込める形で1つのテーブルのように扱えます。

つまずきやすい設定・注意点

カラム数・データ型が一致しないとエラーになる

❌ Before:連結するSELECT文同士でカラム数や順序が揃っていない

SELECT customer_name, amount FROM orders_2025
UNION ALL
SELECT amount, customer_name FROM orders_2026;

私が実際にこの書き方でハマったことがあります。
2つのSELECT文自体はどちらもエラーなく実行できるのですが、orders_2025側は「顧客名・金額」の順、orders_2026側は「金額・顧客名」の順でカラムを書いてしまっていました。
UNIONはカラム名ではなく位置(何番目のカラムか)で結果を連結するため、エラーにはならないまま、金額の列に顧客名の文字列が紛れ込むという気づきにくい不具合になりました。

✅ After:カラムの並び順と型を両方のSELECT文で揃える

SELECT customer_name, amount FROM orders_2025
UNION ALL
SELECT customer_name, amount FROM orders_2026;

UNIONを使う際は、「カラム名を合わせる」だけでなく「カラムの並び順を合わせる」ことを必ず意識してください。
カラム数が異なる場合はERROR 1222: The used SELECT statements have a different number of columnsという分かりやすいエラーになりますが、順序違いはエラーにならないため、より注意が必要です。

パフォーマンスを考えずにUNIONを多用する

UNIONは重複除去のために内部でソート処理を行うため、UNION ALLより処理コストが高くなります。
「重複が発生しないことが分かっている」「重複していても問題ない」場合は、無条件にUNIONを使うのではなくUNION ALLを選ぶ方がパフォーマンス面で有利です。

❌ 重複が発生しないと分かっているのにUNIONを使う
SELECT id FROM orders_2025
UNION
SELECT id FROM orders_2026;

✅ 主キーが年度テーブルごとに独立していて重複しないなら UNION ALL で十分
SELECT id FROM orders_2025
UNION ALL
SELECT id FROM orders_2026;

応用・一歩先の使い方

ORDER BYは最後のSELECT文の後にまとめて書く

UNIONで連結した結果全体を並び替えたい場合、ORDER BYは最後のSELECT文の後に1回だけ書きます。

SELECT customer_name, amount FROM orders_2025
UNION ALL
SELECT customer_name, amount FROM orders_2026
ORDER BY amount DESC;

各SELECT文ごとに個別のORDER BYを書くことはできない点に注意してください。

JOINとの使い分け

JOINとUNIONは混同されがちですが、目的が異なります。

JOINUNION
結合の方向横(カラムを増やす)縦(行を増やす)
使う場面関連する複数テーブルの情報を1行にまとめたい構造が似た複数の結果セットを1つのリストにまとめたい
例会員テーブルと注文テーブルを顧客IDで結合する年度別に分かれた注文テーブルを1つの一覧にする

「関連する情報を横に並べたいのか」「似た構造のデータを縦に積み上げたいのか」で、JOINとUNIONのどちらを使うべきかを判断しましょう。

まとめ

この記事のポイント

  • UNIONは複数のSELECT結果を縦に連結し、重複行を自動的に除去する
  • UNION ALLは重複除去をせず、全件をそのまま連結する
  • 連結するSELECT文はカラム数・並び順・データ型を揃える必要がある
  • 重複が発生しない、または問題ない場合はUNION ALLの方がパフォーマンスに有利

次に読むべき記事

  • SQL 複数テーブル JOIN
  • SQL 自己結合 SELF JOIN
  • SQL GROUP BY 使い方

タグ: SQL, 中級者向け, JOIN

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