ITの教科書検索
入門読了 約11分

SQLのUNIONとは ― UNION ALL・JOINとの違い

UNIONは2つのSELECTの結果を縦につなぎ、重複行を消します。UNION ALLとの違い、JOINとの使い分け、列の数や型が合わないエラーの直し方が分かります。

目次
  1. SQLのUNIONとは
  2. UNIONの書き方と結果
  3. UNIONとUNION ALLの違い
  4. 演算を選んで結果を比べる
  5. 列の数と型の条件
  6. JOINとの違いと使い分け
  7. INTERSECTとEXCEPT
  8. ORDER BYを書く位置
  9. よくあるエラーと直し方
  10. 練習問題

SQLのUNIONとは、SELECTの結果を縦につなぐ演算子

SQLのUNIONは、2つのSELECT文の結果を縦につなぎ、1つの結果にする演算子です。売上が年ごとに別のテーブルに分かれていて、全部の年を1つの一覧で見たいときに使います。

気をつけたいのは、UNIONが重複した行を黙って消すことです。同じ商品が同じ金額で売れた行が1行に減るので、そのまま合計すると売上が足りなくなります。UNION ALLとの違い、JOINとの使い分け、列の数や型が合わないエラーの直し方も、同じ売上の例で説明します。

UNIONの書き方は、2つのSELECTの間にUNIONを置くだけ

売上を年ごとのテーブルに分けて持っている例で試します。売上2025テーブルは次の3行です。

売上2025テーブル
注文番号商品名金額
1001マウス1000
1002キーボード2500
1003マウス1000

売上2026テーブルも同じ3列で、次の3行です。

売上2026テーブル
注文番号商品名金額
2001マウス1000
2002キーボード2800
2003スピーカー2000

2つのSELECT文の間にUNIONを書くと、結果が1つになります。文の終わりのセミコロンは、最後に1つだけ書きます。

SELECT 商品名, 金額
FROM 売上2025
UNION
SELECT 商品名, 金額
FROM 売上2026;
UNIONの実行結果
商品名金額
マウス1000
キーボード2500
キーボード2800
スピーカー2000

2つのテーブルを合わせると6行あるのに、結果は4行です。マウス 1000の3行が、1行にまとまったからです。キーボードは金額が違うので、別の行として2行残ります。

3年分をつなぐときは、続けてUNIONとSELECT文を書きます。PostgreSQLの文書によると、複数のUNIONは左から順に処理します。

UNIONとUNION ALLの違いは、重複した行を消すかどうか

UNIONは重複した行を1行にまとめ、UNION ALLは全ての行をそのまま残します。同じ2つのテーブルで比べると、次のようになります。

UNIONとUNION ALLの比較
比べる点UNIONUNION ALL
重複した行1行にまとめるそのまま残す
売上の例の行数4行6行
売上の例の合計830010300
処理の手間重複を探す分だけ増えるつなぐだけで済む

売上の合計は、UNIONを使うと2000少なくなります。エラーは出ないので、数字が合わないことに気づくまで間違いが残ります。別々の注文を全て数える集計には、UNION ALLを使います。

SELECT SUM(金額) AS 合計
FROM (
  SELECT 商品名, 金額
  FROM 売上2025
  UNION ALL
  SELECT 商品名, 金額
  FROM 売上2026
) AS 全売上;
-- 結果:10300

FROMの中のSELECT文はサブクエリで、つないだ結果を1つの表として扱えます。SUMは集約関数なので、GROUP BYを足すと商品ごとの合計も出せます。

UNION ALLは、つないだ結果から重複を探す処理をしません。PostgreSQLの文書も、UNION ALLはふつうUNIONよりかなり速いと書き、使えるときはALLを使うよう勧めています。重複を消す必要があるときだけ、UNIONを選びます。

重複かどうかは、SELECTで選んだ全ての列の値で決まります。注文番号も選ぶと、どの行も値が違うので、UNIONでも6行全てが残ります。消えるのは2つの結果の間の重複だけではありません。売上2025の中にあるマウス 1000の2行も、1行になります。

NULLどうしは、UNIONでは同じ値として扱います。SELECT NULL UNION SELECT NULL の結果は1行です。NULLを=で比べても一致しないWHERE句とは、動きが違います。

演算を選んで、残る行と合計を比べる

次の図で売上の2つのテーブルをつなぐ演算を選ぶと、入力の行が残るかどうかと、結果の行数・合計が切り替わります。結果は、PostgreSQLで実際に実行して確かめたものです。

2つのSELECTをつなぐ演算
SELECT 商品名, 金額
FROM 売上2025
UNION ALL
SELECT 商品名, 金額
FROM 売上2026;
売上2025
  • 1001マウス1000残る
  • 1002キーボード2500残る
  • 1003マウス1000残る
売上2026
  • 2001マウス1000残る
  • 2002キーボード2800残る
  • 2003スピーカー2000残る
結果(6行、金額の合計 10300)
  1. マウス1000
  2. キーボード2500
  3. マウス1000
  4. マウス1000
  5. キーボード2800
  6. スピーカー2000

全ての行がそのまま残ります。マウス 1000は3行とも結果に出ます。

結果の行は、見やすいように入力の表の順に並べています。

UNIONでつなぐ列は、数と型をそろえる

つなぐSELECTどうしは、列の数が同じで、対応する列の型が互換でなければなりません。互換とは、1つの列にまとめられる型のことです。PostgreSQLでは整数の列と小数の列はつなげますが、整数の列と文字列の列をつなぐとエラーになります。

MySQLの文書は、対応する列を同じ型にするよう書いています。型が合わないときは、全てのSELECTの値を踏まえて結果の型と長さを決めるとも説明しています。製品によって動きが違うので、同じ型にそろえて書いておくと安全です。

列は名前ではなく、左から何番目かで対応します。名前が違っていてもつながり、結果の列名は最初のSELECTの列名になります。次の文の結果の列名は、商品名と売上額です。

SELECT 商品名, 金額 AS 売上額
FROM 売上2025
UNION ALL
SELECT 商品名, 金額
FROM 売上2026;

列の順番を取り違えても、型が同じならエラーになりません。例えば、注文番号と金額はどちらも整数です。片方のSELECTだけ順番を逆に書くと、金額の列に注文番号が入ったまま結果が返ります。

片方のテーブルにしかない列は、もう片方のSELECTにNULLや固定の値を書いて、列の数をそろえます。固定の値の列は、どの年の行かを見分ける目印にも使えます。

SELECT 商品名, 金額, 2025 AS 年
FROM 売上2025
UNION ALL
SELECT 商品名, 金額, 2026
FROM 売上2026;

JOINは横に、UNIONは縦につなぐ

UNIONは行を増やし、JOINは列を増やします。どちらも2つの表をまとめますが、できあがる表の形が違います。

UNION ALL:行が増える商品名金額マウス1000キーボード2500マウス1000マウス1000キーボード2800スピーカー2000売上2025売上20262列のまま、3行に3行を足して6行JOIN:列が増える売上2026商品商品名金額分類マウス1000入力機器キーボード2800入力機器スピーカー2000音響機器3行のまま、2列に1列を足して3列
同じ売上のデータで比べた結果です。色の付いた部分が、もう一方の表から足された行と列です。

同じ列を持つデータが複数のテーブルに分かれているなら、UNIONを使います。行に別のテーブルの情報を足したいなら、JOINを使います。売上の行に商品の分類を足す処理はJOINで、2025年と2026年の売上を1つの一覧にする処理はUNIONです。

UNIONとJOINの比較
比べる点UNIONJOIN
増えるもの行列
つなぎ方左から何番目かで列を合わせるONの条件で行を合わせる
向いている場面同じ形のデータが複数の表に分かれている行に別の表の情報を足したい

2つの年の売上をJOINでつなぐと、2025年の列の右に2026年の列が並びます。全部の年を1つの列に縦に並べたいときは、UNIONを使います。JOINでも、相手の表に一致する行が複数あれば行は増えます。

INTERSECTは両方にある行、EXCEPTは片方だけにある行を返す

UNIONと同じ書き方で使える演算子が、ほかに2つあります。INTERSECTは両方の結果にある行を返します。EXCEPTは、先のSELECTの結果にあって、後のSELECTの結果に無い行を返します。

UNION・INTERSECT・EXCEPTと集合演算の対応
演算子返す行集合演算売上の例の結果
UNIONどちらかの結果にある行和4行
INTERSECT両方の結果にある行積マウス 1000
EXCEPT先の結果にあり、後の結果に無い行差キーボード 2500

EXCEPTは、書く順番で結果が変わります。演算を選ぶ図で「EXCEPT(順番を逆に)」を押すと、残る行が入れ替わることを確かめられます。PostgreSQLとMySQLでは、どの演算子も既定で重複を消し、ALLを付けると重複した行を残します。

MySQLでINTERSECTとEXCEPTを使えるのは、8.0.31以降です。MySQLの文書によると、Oracleなどの一部の製品はEXCEPTをMINUSと呼びます。MySQLではMINUSを使えず、PostgreSQLで実行しても構文エラーになりました。和・積・差という集合演算の考え方は、関係演算の記事で説明しています。

ORDER BYは文の最後に1回だけ書く

ORDER BYは文の最後に書き、つないだ結果の全体を並べ替えます。WHEREはSELECTごとに書き、そのSELECTの行だけを絞ります。次の文は、2000以上の売上を年に関係なく金額の高い順に並べます。

SELECT 商品名, 金額FROM 売上2025WHERE 金額 >= 2000UNION ALLSELECT 商品名, 金額FROM 売上2026WHERE 金額 >= 2000ORDER BY 金額 DESC;売上2025の行を絞る売上2026の行を絞る全体を並べ替えるSELECT 商品名, 金額FROM 売上2025WHERE 金額 >= 2000UNION ALLSELECT 商品名, 金額FROM 売上2026WHERE 金額 >= 2000ORDER BY 金額 DESC;売上2025の行を絞る売上2026の行を絞る全体を並べ替える
括弧で示した範囲に、それぞれのWHEREとORDER BYが効きます。

結果は、キーボード 2800、キーボード 2500、スピーカー 2000の3行です。ORDER BYを書かないと、行の順番は決まりません。1つ目のSELECTの行が先に並ぶとも限らないので、順番が必要なら必ず書きます。

年ごとに金額の最も高い1行を取りたいときは、途中のSELECTにもORDER BYが必要です。その場合は、SELECT文を括弧で囲みます。LIMIT 1は、先頭の1行だけを返す指定です。

(SELECT 商品名, 金額
 FROM 売上2025
 ORDER BY 金額 DESC LIMIT 1)
UNION ALL
(SELECT 商品名, 金額
 FROM 売上2026
 ORDER BY 金額 DESC LIMIT 1);
-- 結果:キーボード 2500
--       キーボード 2800

MySQLの文書は、括弧の中のORDER BYが最終的な順番を決めるとは限らないと書いています。LIMITと組み合わせて行を選ぶために使い、全体の順番は最後のORDER BYで決めます。

UNIONのエラーは、列の数・型・ORDER BYの位置を確かめる

次の表のPostgreSQLのエラーの文は、実際に実行して出たものです。MySQLのエラーの文は、公式のエラー一覧から引きました。

UNIONでよく出るエラーの文と、原因と直し方
エラーの文原因直し方
each UNION query must have the same number of columnsPostgreSQLで、列の数がSELECTごとに違う少ない側にNULLや固定の値の列を足す
The used SELECT statements have a different number of columnsMySQLで、同じく列の数が違う上と同じ
UNION types text and integer cannot be matched対応する列の型が合わない列の順番を見直す。順番が正しければ、CASTで型をそろえる
syntax error at or near "UNION"途中のSELECTにORDER BYを書いた最後に移すか、SELECTを括弧で囲む
column "金額" does not existORDER BYに、最初のSELECTに無い列名を書いた最初のSELECTの列名を書く
invalid UNION/INTERSECT/EXCEPT ORDER BY clauseORDER BYに式を書いた計算した値に列名を付けて、その名前で並べ替える

文字列の列と整数の列をあえてつなぐときは、CAST(金額 AS text) のように型を変えて書きます。ORDER BYに書けるのは、PostgreSQLでは結果の列名か列番号だけです。MySQLでは列番号の指定は非推奨で、売上2025.金額 のような表名付きの列名も書けません。

参考にした資料

練習問題(全5問)

Q12つのテーブルの売上を1つの一覧にして、金額を合計したい。別々の注文が同じ商品・同じ金額のこともある。使う演算子はどれ?
Q2SELECT 商品名 FROM 売上2025 UNION SELECT 商品名 FROM 売上2026; で、売上2025にはマウスが2行、売上2026にはマウスが1行ある。結果にマウスは何行出る?
Q3SELECT 商品名, 金額 FROM 売上2025 UNION SELECT 商品名 FROM 売上2026; を実行すると、どうなる?
Q4売上の行に、商品の表の分類の列を足して見たい。使うのはどれ?
Q5UNIONでつないだ全体を金額の順に並べたい。ORDER BYはどこに書く?

選んでから「採点する」を押すと、解説つきで答え合わせができます。

関連記事

おすすめの本 PR

セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

目的別の本の選び方を見る

データベースの記事を続けて読む

データベース 全36本中17本目