【MySQL】UNION や UNION ALL で複数のテーブルをまとめて検索する

  • 2022年5月9日
  • 2022年5月9日
  • SQL

 データベース内ではしばしば共通項を持つが別のモノなので別のテーブルを定義する、ということをします。例えば、次のER図です。

 こういった構造のデータベースの上で両方のテーブルの会員をまとめて検索したい、といった要望が出てくる時があります。この要望を実現するよくある方法は WHERE、OFFSET、LIMIT あたりを組み合わせたひとつの SQL を発行する方法ですが、これをすんなり使うことはできません。各テーブルのクエリ結果についてどれが何件目で今なん件表示できるデータがそろっているのか、二つの結果をどうやって一つの表にまとめるか、で苦労します。解決方法の一つとして次のER図の様にデータベースの構造に検索用のテーブルを追加する、あるいは元のテーブルを変更する方法があります。

 こうすると次の様なクエリで共通項のみの検索ができます。共通項のみのテーブル上でインデックスを使えるので SQL の実行時間を短くするのも比較的容易です。

SELECT *
FROM member_names
WHERE name LIKE '佐藤%'
ORDER BY name
LIMIT 30 OFFSET 60; # 1ページ件数30件の3ページ目

 しかしながら、様々な理由でその様なデータベースの構造の変更ができない場合もあります。そういった際には UNION、UNION ALL といった句で複数の結果をまとめてその上で OFFSET、LIMIT を使う方法があります。これは次の様にできます。

(SELECT
     # UNION, UNION ALL は同じ列を持つ SELECT 結果をまとめます。
     # ある SELECT 結果特有の列をまとめた結果にも用いるならば、他の SELECT 結果で null 埋め列を作るのが手軽です。
     # ここでは商業会員になくゲスト会員にある列である guest_member_id を2列目として null 埋めをしています。
     commerce_member_id,
     null as guest_member_id,
     name
 FROM commerce_members
 WHERE name LIKE '%高%' # WHERE は個々のクエリに書く必要があります。
)
# @see https://dev.mysql.com/doc/refman/8.0/ja/union.html
# UNION ALL で同じ内容の行の重複を許してまとめます。
# 単に UNION とすると重複を除去します。
UNION ALL
(SELECT null,
        guest_member_id,
        name
 FROM guest_members
 WHERE name LIKE '%高%')
# 個々のクエリを括り、最後に ORDER BY, LIMIT, OFFSET を書くと
# UNIONした結果に ORDER BY, LIMIT, OFFSET が適用されます。
ORDER BY name
LIMIT 2 OFFSET 2 # 1ページ件数2件の2ページ目

デモ用SQL全体
create table commerce_members
(
    commerce_member_id int auto_increment,
    name               varchar(255) not null comment '名前',
    commerce_id        varchar(255) not null comment '商業ID',
    commerce_spacial_1 int default null comment '商業会員特有カラム1',
    commerce_spacial_2 int default null comment '商業会員特有カラム2',
    commerce_spacial_3 int default null comment '商業会員特有カラム3',
    commerce_spacial_4 int default null comment '商業会員特有カラム4',
    commerce_spacial_5 int default null comment '商業会員特有カラム5',
    created_at         datetime     null,
    updated_at         datetime     null,
    constraint commerce_members_pk
        primary key (commerce_member_id)
);

alter table commerce_members comment '商業会員';

INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (1, '今野 角太郎', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (2, '上田 倉美', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (3, '古田 新太郎', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (4, '吉本 兼典', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (5, '日高 義隆', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (6, '本間 僧三郎', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (7, '根岸 三平', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (8, '藤沢 なつみ', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (9, '野村 敬吉', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (10, '平山 朋子', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (11, '上原 道正', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (12, '石山 美世', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (13, '植田 伴助', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (14, '松山 麻琴', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (15, '大橋 知美', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (16, '村山 裕史', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (17, '岡部 光善', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (18, '堀内 昭子', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (19, '宮内 正進', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (20, '三木 禎二', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (21, '高山 信弥', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (22, '竹内 政年', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (23, '村瀬 理香', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (24, '細川 真人', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (25, '高井 清一', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (26, '菅野 今朝雄', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');
INSERT INTO commerce_members (commerce_member_id, name, commerce_id, commerce_spacial_1, commerce_spacial_2, commerce_spacial_3, commerce_spacial_4, commerce_spacial_5, created_at, updated_at) VALUES (27, '相馬 茂一', 'exampleID', null, null, null, null, null, '2022-05-09 11:02:34', '2022-05-09 11:02:36');

create table guest_members
(
    guest_member_id int auto_increment,
    name               varchar(255) not null comment '名前',
    guest_spacial_1 int default null comment 'ゲスト会員特有カラム1',
    guest_spacial_2 int default null comment 'ゲスト会員特有カラム2',
    guest_spacial_3 int default null comment 'ゲスト会員特有カラム3',
    guest_spacial_4 int default null comment 'ゲスト会員特有カラム4',
    guest_spacial_5 int default null comment 'ゲスト会員特有カラム5',
    created_at         datetime     null,
    updated_at         datetime     null,
    constraint guest_members_pk
        primary key (guest_member_id)
);

alter table guest_members comment 'ゲスト会員';

INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (1, '宮沢 玲子', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (2, '榎本 準郎', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (3, '星野 成男', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (4, '萩原 利次', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (5, '本田 利浩', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (6, '塚田 佳久', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (7, '花田 好行', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (8, '森 幸博', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (9, '沢田 知明', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (10, '柴田 喜重', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (11, '中尾 慶太郎', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (12, '渋谷 勝行', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (13, '渋谷 幾江', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (14, '谷 ハルノ', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (15, '吉井 絵里', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (16, '松尾 恒宏', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');
INSERT INTO guest_members (guest_member_id, name, guest_spacial_1, guest_spacial_2, guest_spacial_3, guest_spacial_4, guest_spacial_5, created_at, updated_at) VALUES (17, '岡崎 三男', null, null, null, null, null, '2022-05-09 11:06:31', '2022-05-09 11:06:31');

(SELECT
     # UNION, UNION ALL は同じ列を持つ SELECT 結果をまとめます。
     # ある SELECT 結果特有の列をまとめた結果にも用いるならば、他の SELECT 結果で null 埋め列を作るのが手軽です。
     # ここでは商業会員になくゲスト会員にある列である guest_member_id を2列目として null 埋めをしています。
     commerce_member_id,
     null as guest_member_id,
     name
 FROM commerce_members
 WHERE name LIKE '%高%' # WHERE は個々のクエリに書く必要があります。
)
# @see https://dev.mysql.com/doc/refman/8.0/ja/union.html
# UNION ALL で同じ内容の行の重複を許してまとめます。
# 単に UNION とすると重複を除去します。
UNION ALL
(SELECT null,
        guest_member_id,
        name
 FROM guest_members
 WHERE name LIKE '%高%')
# 個々のクエリを括り、最後に ORDER BY, LIMIT, OFFSET を書くと
# UNIONした結果に ORDER BY, LIMIT, OFFSET が適用されます。
ORDER BY name
LIMIT 2 OFFSET 2 # 1ページ件数2件の2ページ目


 これにより一つのクエリで複数のテーブルをまとめて検索できます。
 
 ちなみに PHP フレームワークの Laravel では次の様に union メソッドとクエリオブジェクトを組み合わせることで UNION 句を使えます。
データベース:クエリビルダ 9.x Laravel

use Illuminate\Support\Facades\DB;

$first = DB::table('users')
            ->whereNull('first_name');

$users = DB::table('users')
            ->whereNull('last_name')
            ->union($first)
            ->get();
>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG