コマンド道場

UNION / UNION ALL(2 つの結果を縦につなぐ)の使い方

2 つの結果を縦につなぐ

shain給与 50 万以上

name
中村
井上
山本

shain在籍中

name
中村
井上
吉田

UNIONどちらかに当てはまる人

name
吉田
山本
中村
井上
  • 給与 50 万以上 10 在籍中 16どちらかに当てはまる人 17
  • そのまま積むと 26 行ですが、両方にある 9 行が 1 つにまとめられて 17 行になります(9 行ぶん減ります)

10 人と 16 人をつないだのに 26 人ではなく 17 人です。両方に入っている 9 人が 1 人ずつにまとめられたからです。

UNION は 2 つの結果を縦につなぎます。 結合が列を増やすのに対し、集合演算は行を増やしますUNION は重複を 1 つにまとめ、UNION ALL はまとめません。違いはそれだけですが、件数が変わるので取り違えると結果が狂います。

未確認の製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database

未確認: IBM Db2

製品ごとの対応表(根拠つき)を見る

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01結合は列が増え、集合演算は行が増える

結論: UNION は 2 つの結果を上下に積み重ねます。

結合(JOIN)と混同しやすいので、先にここを分けておきます。

  • 結合 … 行と行を横につなぐ。列が増える
  • 集合演算 … 結果を縦につなぐ。行が増える

縦に積むので、左右の列の数と型が揃っている必要があります。「社員名の一覧」と「社員名の一覧」なら積めますが、「社員名」と「給与」は積めません。

⚠️ 同じ表から 2 回取り出しても構いません。冒頭の図がまさにそれで、shain から「給与 50 万以上」と「在籍中」を別々に取り出して積んでいます。

1 行ずつ、何をしているか
  1. SELECT name FROM shain1 つ目の問い合わせ
  2. WHERE salary >= 500000給与 50 万以上
  3. UNION★ここで縦につなぐ(重複は 1 つに)
  4. SELECT name FROM shain2 つ目の問い合わせ
  5. WHERE taishoku_on IS NULL在籍中
  6. ORDER BY 1;★並べ替えは最後に 1 つだけ

1 つ目と 2 つ目は、それぞれ独立した SELECT です。ORDER BY だけは全体に 1 つ書きます。

どちらかに当てはまる人
SELECT name FROM shain WHERE salary >= 500000
UNION
SELECT name FROM shain WHERE taishoku_on IS NULL
ORDER BY 1;
name
中村
井上
伊藤
佐藤
加藤
吉田
大野
小林
山本
山田
斎藤
木村
松本
清水
渡辺
田中
鈴木

17

17 人です。給与 50 万以上が 10 人、在籍中が 16 人なので、単純に足すと 26 人になるはずですが、そうはなりません。

02UNION は重複を消し、UNION ALL は消さない

結論: UNION は重複した行を 1 つにまとめます。UNION ALL はそのまま残します。

いちばん分かりやすいのは、まったく同じ問い合わせを 2 つつなぐことです。UNION なら結果は 1 行、UNION ALL なら 2 倍の行数になります。

⚠️ 重複とは「行がまるごと同じ」ことです。選んでいる列の値がすべて一致したときだけ、まとめられます。列を 1 つ足すと重複でなくなることがあります。

⚠️ 消えるのは片側だけにある重複も同じです。1 つ目の問い合わせが同じ値を 2 行返していれば、それも 1 行にまとめられます。

同じ問い合わせを UNION でつなぐ
SELECT busho_id FROM shain WHERE busho_id = 2
UNION
SELECT busho_id FROM shain WHERE busho_id = 2;
busho_id
2

1

1 行です。開発には 4 人いて左右とも 4 行返しますが、値がすべて 2 なので 1 行にまとめられます。

同じ問い合わせを UNION ALL でつなぐ
SELECT busho_id FROM shain WHERE busho_id = 2
UNION ALL
SELECT busho_id FROM shain WHERE busho_id = 2;
busho_id
2
2
2
2
2
2
2
2

8

8 行です。4 行と 4 行がそのまま積み重なりました。上の例と SQL の違いは ALL の 3 文字だけです。

03迷ったら UNION ALL を使う

結論: 重複を消す必要が無いなら UNION ALL を選びます。

UNION は重複を消すために、結果を全部並べ替えるか集計する必要があります。行数が多いほど余計な仕事が増えます。

一方 UNION ALL はただ積むだけです。重複が起きえないと分かっている場合(期間で分けた集計をつなぐ、種類の違う一覧を並べる等)は、UNION ALL のほうが素直です。

「とりあえず UNION」と書く癖は避けてください。 重複を消したいという意図が無いのに消していると、件数が合わない原因を探すときに手がかりを失います。

種類の違う一覧を区分つきで並べる
SELECT name, '給与上位' AS kubun FROM shain WHERE salary >= 700000
UNION ALL
SELECT name, '所属なし' FROM shain WHERE busho_id IS NULL
ORDER BY 2, 1;
namekubun
大野所属なし
渡辺所属なし
佐藤給与上位
山田給与上位
鈴木給与上位

5

5 行です。区分の列を足しているので、仮に同じ人が両方に出てきても別の行として残ります。重複を消す理由がないので UNION ALL です。

04⚠️ よくある間違い:列の数と型が揃っていないと落ちる

結論: 縦に積む以上、左右の列の数と型は揃っていなければなりません。

揃っていないとエラーになります。動いてから気づくのではなく、書いた時点で数えてください。

よくあるのは、片側にだけ列を足してしまう間違いです。列を足すときは必ず両側に足します

型については、数値と文字列のように変換できない組み合わせだと落ちます。どうしても混ぜたいときは、片側を明示的に変換します。

列の数が違う
SELECT name FROM shain
UNION
SELECT name, salary FROM shain;
ERROR: each UNION query must have the same number of columns

「same number of columns」と出ます。1 列と 2 列は積めません。

列の型が違う
SELECT name FROM shain
UNION
SELECT salary FROM shain;
ERROR: UNION types text and numeric cannot be matched

「types text and numeric cannot be matched」と出ます。名前の列と給与の列は積めません。

05列名は 1 つ目の問い合わせのものになる

結論: 結果の列名は 1 つ目の SELECT で決まります。 2 つ目に付けた別名は使われません。

見出しが思ったものと違うときは、2 つ目に別名を書いていないかを疑ってください。直すのは 1 つ目です。

⚠️ 列の並び順も 1 つ目が基準です。左右で列の順番を入れ違えても、数と型さえ合っていればエラーにならず、値だけが入れ替わった結果が返ります。これは機械では見つけられないので、書いたら順番を目で確かめてください。

2 つ目の別名は使われない
SELECT name AS hidari FROM shain WHERE salary >= 700000
UNION
SELECT name AS migi FROM shain WHERE busho_id = 7
ORDER BY 1;
hidari
井上
佐藤
山田
木村
鈴木

5

見出しは hidari です。migi はどこにも出てきません。

06⚠️ よくある間違い:ORDER BY は最後に 1 つだけ

結論: 並べ替えは全体に対して 1 つだけ、いちばん最後に書きます。

1 つ目の SELECT の後ろに ORDER BY を書くとエラーになります。「1 つ目だけ並べる」ということができないためです。

⚠️ 並べ替えの対象は結果の列なので、1 つ目の列名か、列番号で指定します。ORDER BY 1 のように番号で書けるのはこの場面で便利です。

途中に ORDER BY を書く
SELECT name FROM shain ORDER BY name
UNION
SELECT name FROM shain;
ERROR: syntax error at or near "UNION"

構文エラーになります。UNION の前で並べ替えることはできません。

最後に 1 つだけ書く
SELECT name FROM shain WHERE salary >= 700000
UNION
SELECT name FROM shain WHERE busho_id = 7
ORDER BY 1;
name
井上
佐藤
山田
木村
鈴木

5

5 人です。ORDER BY 1 は「結果の 1 列目」という意味で、ここでは name のことです。

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

関連するトピック

  • INTERSECT両方にある行だけを残す集合演算です。
  • EXCEPT片方にしかない行を残す集合演算です。
  • DISTINCT1 つの問い合わせの中で重複を消す書き方です。
  • INNER JOIN行を横につなぐほうの操作です。
  • ORDER BY 句並べ替えそのものはこちらです。

根拠(一次情報)