トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

7-13 和集合を作成してmerge

SQLパズル

テーブルA
Code  Name
----  ------
1     吉法師
2     日吉丸
3     竹千代
5     源頼朝

テーブルB
Code  Name       Nen
----  --------   ----
1     織田信長   1582
2     木下秀吉   1555
3     松平元康   1560
4     遮那王     1175
6     服部半蔵   1582

テーブルC
Code  Name       Nen
----  --------   ----
2     羽柴秀吉   1582
3     徳川家康   1600
4     源義経     1175
7     明智光秀   1600

テーブルAに、
テーブルBの全レコードと、
テーブルCの全レコードを追加更新(merge)する。
ただし、テーブルBとテーブルCに同じCodeが存在したら、
Nenの新しいほうを優先する、Nenが等しかったらテーブルCを優先する

テーブルA、テーブルB、テーブルCのプライマリキーは、Codeとする

Merge後のテーブルA
Code  Name
----  --------
1     織田信長
2     羽柴秀吉
3     徳川家康
4     源義経
5     源頼朝
6     服部半蔵
7     明智光秀


データ作成スクリプト

create table テーブルA(
Code number(1),
Name char(8),
primary key(Code));

create table テーブルB(
Code number(1),
Name char(8),
Nen  char(4),
primary key(Code));

create table テーブルC(
Code number(1),
Name char(8),
Nen  char(4),
primary key(Code));

insert into テーブルA values(1,'吉法師');
insert into テーブルB values(1,'織田信長','1582');
insert into テーブルA values(2,'日吉丸');
insert into テーブルB values(2,'木下秀吉','1555');
insert into テーブルC values(2,'羽柴秀吉','1582');
insert into テーブルA values(3,'竹千代');
insert into テーブルB values(3,'松平元康','1560');
insert into テーブルC values(3,'徳川家康','1600');
insert into テーブルB values(4,'遮那王'  ,'1175');
insert into テーブルC values(4,'源義経'  ,'1175');
insert into テーブルA values(5,'源頼朝');
insert into テーブルB values(6,'服部半蔵','1582');
insert into テーブルC values(7,'明智光秀','1600');
commit;


SQL

--■■■グループ化する方法■■■
merge into テーブルA a
using (select Code,
       max(Name) Keep(Dense_Rank First order by Nen desc,ID desc) as Name
         from (select 1 as ID,Code,Name,Nen from テーブルB union all
               select 2 as ID,Code,Name,Nen from テーブルC)
       group by Code) d
on (a.Code=d.Code)
when matched then
update set a.Name=d.Name
when not matched then
insert(a.Code,a.Name) values(d.Code,d.Name);

--■■■exists述語を使う方法■■■
merge into テーブルA a
using (select b.Code,b.Name from テーブルB b
        where not exists(select 1 from テーブルC c
                          where c.Code=b.Code
                            and c.Nen >= b.Nen)
       union all
       select c.Code,c.Name from テーブルC c
        where not exists(select 1 from テーブルB b
                          where b.Code=c.Code
                            and c.Nen < b.Nen)) d
on (a.Code=d.Code)
when matched then
update set a.Name=d.Name
when not matched then
insert(a.Code,a.Name) values(d.Code,d.Name);


解説

exists述語を使う方法では、
mergeのusing句で、ブール代数の補元法則を使ってます。