MariaDB講座 / UNION・UNION ALLで問い合わせ結果をつなぐ

UNIONは対応する列を持つ結果を縦につなぎ、選択値の重複した組を除きます。UNION ALLは重複を残します。列数・位置・意味をそろえ、必要な順番は最後のORDER BYで指定します。

縦の結合と関連列の結合を分ける

顧客へ注文情報を横に付けるのはJOIN、ソウル顧客と支払い済み顧客を対象一覧にまとめるのはUNIONです。両方整数でも、顧客IDと注文IDは同じ列位置に混ぜられる意味ではありません。

重複判定はDISTINCTと同様に選択した値の組全体です。UNION ALLが重複除去の負担を省けても、必要な一意性を捨てれば違う母集団になります。

重なりのある二集団を用意する

クライアントの接続手順でcourse_userとしてshopcourseへ接続し、SELECT VERSION(), DATABASE();とSHOW TABLES;を確認します。以下には必要な四表の作成とデータがすべてあり、以前の記事の表を必要としません。UTF-8の.sqlファイルで実行し、同名の表があれば定義と内容を調べてから判断します。

USE shopcourse;
CREATE TABLE c30_customers (
 customer_id INT NOT NULL PRIMARY KEY,
 customer_name VARCHAR(50) NOT NULL,
 city VARCHAR(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c30_products (
 product_id INT NOT NULL PRIMARY KEY,
 product_name VARCHAR(100) NOT NULL,
 category VARCHAR(30) NOT NULL,
 price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
 stock INT NOT NULL CHECK (stock >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c30_orders (
 order_id INT NOT NULL PRIMARY KEY,
 customer_id INT NOT NULL,
 ordered_at DATETIME NOT NULL,
 status VARCHAR(20) NOT NULL,
 shipping_fee DECIMAL(10,2) NOT NULL DEFAULT 1000,
 CONSTRAINT fk_c30_order_customer FOREIGN KEY (customer_id)
  REFERENCES c30_customers(customer_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE c30_items (
 order_id INT NOT NULL,
 product_id INT NOT NULL,
 quantity INT NOT NULL CHECK (quantity > 0),
 unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0),
 PRIMARY KEY (order_id, product_id),
 CONSTRAINT fk_c30_item_order FOREIGN KEY (order_id)
  REFERENCES c30_orders(order_id) ON DELETE RESTRICT,
 CONSTRAINT fk_c30_item_product FOREIGN KEY (product_id)
  REFERENCES c30_products(product_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO c30_customers VALUES
 (1,'김민수','서울'),(2,'이서연','부산'),
 (3,'박지우','서울'),(4,'최하늘','대전');
INSERT INTO c30_products VALUES
 (1,'노트','문구',3500,20),(2,'볼펜','문구',1500,50),
 (3,'머그컵','생활',8000,12),(4,'스탠드','생활',25000,5);
INSERT INTO c30_orders
 (order_id,customer_id,ordered_at,status,shipping_fee) VALUES
 (101,1,'2026-01-10 10:00:00','paid',1000),
 (102,1,'2026-01-20 11:00:00','paid',1000),
 (103,2,'2026-02-05 12:00:00','paid',1000),
 (104,3,'2026-02-10 13:00:00','canceled',1000);
INSERT INTO c30_items VALUES
 (101,1,2,3500),(101,2,3,1500),(102,3,1,8000),
 (103,1,1,3500),(103,3,2,8000),(104,2,1,1500);

顧客名・都市・商品名は原文の韓国語サンプルです。商品1~4はノート、ペン、マグカップ、ライト、顧客1・3はソウル、2は釜山、4は大田です。文字列を維持して実行し、説明とは安定したIDで照合できます。

ソウル顧客は1・3、paid注文ありは1・2です。後者はEXISTSで選ぶため、顧客1の二注文はその枝の中で二人にはなりません。

UNIONとUNION ALLを比較する

二つの式の違いだけを比べます。

SELECT customer_id FROM c30_customers WHERE city='서울'
UNION
SELECT c.customer_id FROM c30_customers c WHERE EXISTS
 (SELECT 1 FROM c30_orders o WHERE o.customer_id=c.customer_id AND o.status='paid')
ORDER BY customer_id;
SELECT customer_id FROM c30_customers WHERE city='서울'
UNION ALL
SELECT c.customer_id FROM c30_customers c WHERE EXISTS
 (SELECT 1 FROM c30_orders o WHERE o.customer_id=c.customer_id AND o.status='paid')
ORDER BY customer_id;

UNIONは1・2・3の三行、UNION ALLは1・1・2・3の四行です。二つの入力集合の両方へ属する1が、後者には二回残ります。出現回数を数えるか一意な顧客を数えるかを区別します。

出所を加えると同一性が変わる

韓国語のラベルはソウル顧客・支払い済み顧客という意味です。

SELECT customer_id,'서울 고객' AS source_label FROM c30_customers WHERE city='서울'
UNION
SELECT c.customer_id,'결제 고객' FROM c30_customers c WHERE EXISTS
 (SELECT 1 FROM c30_orders o WHERE o.customer_id=c.customer_id AND o.status='paid')
ORDER BY customer_id,source_label;

ラベルが違うため、UNIONでも顧客1は二行残ります。IDだけを重複検査しているわけではありません。一顧客一行に複数の出所を表示したければ、別の集計や表示設計が必要です。

列対応と最終順序を確認する

各枝は同じ列数と対応可能な型を返し、最終列名は通常最初のSELECTに由来します。後の枝の別名で個別に変わるわけではありません。数値と文字を混ぜるなら変換も調べます。

最後のORDER BYが結合全体の順番です。枝の中の並べ替えだけでは全体順を保証しません。枝ごとに上位件数を選ぶ場合は括弧とLIMITの範囲を明示し、最終ソートと分けます。先に各枝を独立に読み、UNION ALLで重なりを観察してから、除去が必要か決めます。元の表を恒久的に合体・削除する操作ではありません。

再実習はDB名、実際の定義と保存行を確認し、必要なデータを保存してから行います。この記事の削除してよい四表だけを、参照する子から親の順に削除します。DROP TABLEは定義とデータを消し、通常のROLLBACKでは戻せません。

DROP TABLE shopcourse.c30_items;
DROP TABLE shopcourse.c30_orders;
DROP TABLE shopcourse.c30_products;
DROP TABLE shopcourse.c30_customers;

関連する公式リファレンス