集合演算 — UNION / INTERSECT / EXCEPT
SQLの集合演算(UNION・INTERSECT・EXCEPT)で、複数のクエリ結果を縦につなぐ・共通部分を取る・差を取る方法を解説します。UNIONとUNION ALLの違いも整理します。
JOIN が複数のテーブルを「横」につなぐのに対し、集合演算は複数のクエリ結果を「縦」に組み合わせます。UNION・INTERSECT・EXCEPT の 3 つを使うと、結果セットどうしを集合として足したり、共通部分や差を取ったりできます。
UNION — 結果を縦につなぐ
UNION は 2 つのクエリ結果を縦に結合します。たとえば「開発部の社員」と「給料 600 以上の社員」を 1 つのリストにまとめる場合です。
SELECT name FROM employees WHERE dept = 'Dev'
UNION
SELECT name FROM employees WHERE salary >= 600;集合演算を使うには、上下のクエリで列の数と型が揃っている必要があります。この例はどちらも name の 1 列なので結合できます。
UNION と UNION ALL の違い
UNION は結合した結果から重複を取り除きます。上の例で、開発部かつ給料 600 以上の人は両方の条件に該当しますが、UNION なら 1 回だけ表示されます。
重複を取り除かず、すべての行をそのまま連結したいときは UNION ALL を使います。
SELECT name FROM employees WHERE dept = 'Dev'
UNION ALL
SELECT name FROM employees WHERE salary >= 600;UNION は重複除去のために内部でソート・比較を行うため、UNION ALL より処理が重くなりがちです。重複が出ないと分かっている場合や、重複を残したい場合は UNION ALL を選ぶと効率的です。
INTERSECT — 共通部分
INTERSECT は 2 つの結果の両方に含まれる行だけを返します。「開発部で、かつ給料 600 以上の社員」を集合として求める例です。
SELECT name FROM employees WHERE dept = 'Dev'
INTERSECT
SELECT name FROM employees WHERE salary >= 600;同じことは WHERE dept = 'Dev' AND salary >= 600 でも書けますが、それぞれの条件が別テーブルや複雑なクエリになる場合、INTERSECT で「共通部分」として表現したほうが分かりやすいことがあります。
EXCEPT — 差
EXCEPT は「上のクエリにあって、下のクエリにない行」を返します。「開発部だが、給料 600 以上ではない社員」を求める例です。
SELECT name FROM employees WHERE dept = 'Dev'
EXCEPT
SELECT name FROM employees WHERE salary >= 600;集合の引き算だと考えると分かりやすいです。データベースによっては EXCEPT を MINUS と呼ぶものもあります(Oracle など)。
並べ替えは最後にまとめて
集合演算の結果全体を並べ替えたいときは、ORDER BY を一番最後に 1 つだけ書きます。
SELECT name, salary FROM employees WHERE dept = 'Dev'
UNION
SELECT name, salary FROM employees WHERE salary >= 600
ORDER BY salary DESC;各クエリの途中に ORDER BY は書けません(結合後の全体に対して並べ替えるため)。
まとめ
- 集合演算は複数のクエリ結果を「縦」に組み合わせる(列数・型を揃える)
UNIONは重複を除く、UNION ALLは重複を残す(こちらのほうが速い)INTERSECTは共通部分、EXCEPTは差ORDER BYは結合後の全体に対して最後に 1 つ
JOIN(横のつながり)と集合演算(縦の組み合わせ)を使い分けられると、データの取り出し方の引き出しが増えます。