前回は、行数を限定しデータを取得できる OFFSET ~ FETCH とROWNUMについて説明しました。今回は、2つのSELECT文からそれぞれの検索結果を足し合わせた結果(和集合)を返してくれる、UNION と UNION ALL について説明します。
和集合
| UNION | 
|  | 
| 和集合 2つの検索結果を 足し合わせたもの | 
データ準備
UNION、UNION ALL を試すためにテーブルを作成し、データを追加します。
-- テーブルの作成
-- 家計簿テーブル1
CREATE TABLE household_account1 (
    id INT PRIMARY KEY,
    transaction_date DATE,
    expense VARCHAR2(20),
    memo VARCHAR2(80),
    deposit INT,
    withdrawal INT
);
-- 家計簿テーブル2
CREATE TABLE household_account2 (
    id INT PRIMARY KEY,
    transaction_date DATE,
    expense VARCHAR2(20),
    memo VARCHAR2(80),
    deposit INT,
    withdrawal INT
);
-- データの登録
-- 家計簿テーブル1
INSERT
  ALL INTO household_account1
VALUES
  (1, TO_DATE('2024-02-10', 'YYYY-MM-DD'), '給料', '2月分', 150000, 0)
INTO
  household_account1
VALUES
  (2, TO_DATE('2024-02-13', 'YYYY-MM-DD'), '食費', '昼食(くら寿司)', 0, 1880) 
INTO
  household_account1
VALUES
  (3, TO_DATE('2024-02-25', 'YYYY-MM-DD'), '交際費', '飲み会', 0, 4000)
SELECT
  *
FROM
  DUAL;
-- 家計簿テーブル2
INSERT
  ALL INTO household_account2
VALUES
  (1, TO_DATE('2024-03-10', 'YYYY-MM-DD'), '給料', '3月分', 150000, 0)
INTO
  household_account2
VALUES
  (2, TO_DATE('2024-03-05', 'YYYY-MM-DD'), '交通費', 'バス代', 0, 240) 
INTO
  household_account2
VALUES
  (3, TO_DATE('2024-03-18', 'YYYY-MM-DD'), '交際費', '飲み会', 0, 8000)
SELECT
  *
FROM
  DUAL;| 日付 | 費目 | メモ | 入金額 | 出金額 | 
|---|---|---|---|---|
| 2024/02/10 | 給料 | 2月分 | 150000 | 0 | 
| 2024/02/13 | 食費 | 昼食(くら寿司) | 0 | 1880 | 
| 2024/02/25 | 交際費 | 飲み会 | 0 | 4000 | 
| 日付 | 費目 | メモ | 入金額 | 出金額 | 
|---|---|---|---|---|
| 2024/03/10 | 給料 | 3月分 | 150000 | 0 | 
| 2024/03/05 | 交通費 | バス代 | 0 | 240 | 
| 2024/03/18 | 交際費 | 飲み会 | 0 | 8000 | 
UNION・UNION ALL の使い方
UNION、UNION ALL は下記のように記述します。
SELECT 文1
UNION (ALL)
SELECT 文2UNIONとUNION ALL の違いは重複行をまとめるかまとめないかで、UNIONの場合は重複行を1行にまとめてくれて、UNION ALLの場合は重複行をまとめずにすべてそのまま返してくれます。
まずは UNION ALL で2テーブルを足し合わせた結果を取得してみます。
SELECT
  TO_CHAR(transaction_date, 'YYYY/MM/DD') AS "日付",
  expense AS "費目",
  memo AS "メモ",
  deposit AS "入金額",
  withdrawal AS "出金額"
FROM
  household_account1
UNION ALL
SELECT
  TO_CHAR(transaction_date, 'YYYY/MM/DD') AS "日付",
  expense AS "費目",
  memo AS "メモ",
  deposit AS "入金額",
  withdrawal AS "出金額"
FROM
  household_account2しっかりと2テーブル分のデータが取得できました。
| 日付 | 費目 | メモ | 入金額 | 出金額 | 
|---|---|---|---|---|
| 2024/02/10 | 給料 | 2月分 | 150000 | 0 | 
| 2024/02/13 | 食費 | 昼食(くら寿司) | 0 | 1880 | 
| 2024/02/25 | 交際費 | 飲み会 | 0 | 4000 | 
| 2024/03/10 | 給料 | 3月分 | 150000 | 0 | 
| 2024/03/05 | 交通費 | バス代 | 0 | 240 | 
| 2024/03/18 | 交際費 | 飲み会 | 0 | 8000 | 
では、費目がそれぞれかぶっているので UNION を使って重複行をまとめてみたいと思います。
SELECT
  expense AS "費目"
FROM
  household_account1
UNION
SELECT
  expense AS "費目"
FROM
  household_account2重複行がない費目のデータが取得できました。
| 費目 | 
|---|
| 交通費 | 
| 交際費 | 
| 給料 | 
| 食費 | 
処理速度が高いのは UNION ALL
UNIONはデータの重複を除外するために追加の処理が必要なので、UNION ALL よりも処理に時間がかかります。
下記記事はMySQLですが、UNION と UNION ALL の処理速度の違いを実際に測定しグラフにまとめてくれていたのでわかりやすかったです!

【MySQL】UNION と UNION ALL はどっちが処理速度速いの? - Qiita
はじめにこの記事は ミライトデザイン Advent Calendar 2022 の 20 日目の記事となっています。先日はbucchさんの「ReactでGoogleMapの実装をしてみた」でした!…
まとめ
UNIONは重複行を1行にまとめてくれて、UNION ALL は全てのレコードを返してくれるということを覚えておきましょう!
 
 

