UNION / UNION ALL(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 万以上」と「在籍中」を別々に取り出して積んでいます。
SELECT name FROM shain1 つ目の問い合わせWHERE salary >= 500000給与 50 万以上UNION★ここで縦につなぐ(重複は 1 つに)SELECT name FROM shain2 つ目の問い合わせWHERE taishoku_on IS NULL在籍中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 行にまとめられます。
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 行にまとめられます。
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;| name | kubun |
|---|---|
| 大野 | 所属なし |
| 渡辺 | 所属なし |
| 佐藤 | 給与上位 |
| 山田 | 給与上位 |
| 鈴木 | 給与上位 |
(5 行)
5 行です。区分の列を足しているので、仮に同じ人が両方に出てきても別の行として残ります。重複を消す理由がないので UNION ALL です。
04⚠️ よくある間違い:列の数と型が揃っていないと落ちる
結論: 縦に積む以上、左右の列の数と型は揃っていなければなりません。
揃っていないとエラーになります。動いてから気づくのではなく、書いた時点で数えてください。
よくあるのは、片側にだけ列を足してしまう間違いです。列を足すときは必ず両側に足します。
型については、数値と文字列のように変換できない組み合わせだと落ちます。どうしても混ぜたいときは、片側を明示的に変換します。
SELECT name FROM shain
UNION
SELECT name, salary FROM shain;「same number of columns」と出ます。1 列と 2 列は積めません。
SELECT name FROM shain
UNION
SELECT salary FROM shain;「types text and numeric cannot be matched」と出ます。名前の列と給与の列は積めません。
05列名は 1 つ目の問い合わせのものになる
結論: 結果の列名は 1 つ目の SELECT で決まります。 2 つ目に付けた別名は使われません。
見出しが思ったものと違うときは、2 つ目に別名を書いていないかを疑ってください。直すのは 1 つ目です。
⚠️ 列の並び順も 1 つ目が基準です。左右で列の順番を入れ違えても、数と型さえ合っていればエラーにならず、値だけが入れ替わった結果が返ります。これは機械では見つけられないので、書いたら順番を目で確かめてください。
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 のように番号で書けるのはこの場面で便利です。
SELECT name FROM shain ORDER BY name
UNION
SELECT name FROM shain;構文エラーになります。UNION の前で並べ替えることはできません。
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 句並べ替えそのものはこちらです。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 問い合わせの結合(UNION / INTERSECT / EXCEPT)一次情報・確認 2026-08-11
- PostgreSQL 18 マニュアル: SELECT(UNION 句と ORDER BY の位置)一次情報・確認 2026-08-11