データベースアクセス層(いわゆるDAO)からとあるテーブルの行の更新情報がDBに引き渡されるとします。そのテーブルは主キーによって行が一意に特定されるため、渡された更新情報に含まれる主キーの有無によって、更新と挿入を切り替えます。いいかえれば__「主キーがテーブルに存在するときはupdate
、存在しないときはinsert
」__ということをしたいわけです。たとえば疑似コードで書けば次のようになります。
if (primary_key in table.primary_keys ) then
update table
else
insert table
end
かえってわかりにくいような……。それはさておき、以上のような要件を達成するにはmerge
を利用します。
-- テーブル「tbl」を作成する。
create table tbl (
id varchar(10) not null primary key,
value varchar(10)
);
-- 初期化: テーブルの内容を作成する。
insert into tbl values
('AAA', 'A'),
('BBB', 'B'),
('CCC', 'C');
-- 初期状態を確認しておく。
select * from tbl;
-- updateのサンプル: id = 'AAA'が存在するときはupdate/ないときはinsertしたい。
merge into tbl
using (select 'AAA' as id from sysibm.sysdummy1) as condition
on tbl.id = condition.id
when matched then
update set value = 'updated A'
when not matched then
insert (id, value) values ('AAA', 'inserted A');
-- insertのサンプル: id = 'DDD'が存在するときはupdate/ないときはinsertしたい。
merge into tbl
using (select 'DDD' as id from sysibm.sysdummy1) as condition
on tbl.id = condition.id
when matched then
update set value = 'updated D'
when not matched then
insert (id, value) values ('DDD', 'inserted D');
-- id = 'AAA'が更新され、id = 'DDD'が挿入されていることを確認する。
select * from tbl;
/*
=== 1回目のselect文の結果 ===
select * from tbl
ID VALUE
---------- ----------
AAA A
BBB B
CCC C
3 レコードが選択されました。
=== 2回目のselect文の結果 ===
select * from tbl
ID VALUE
---------- ----------
AAA updated A
BBB B
CCC C
DDD inserted D
4 レコードが選択されました。
*/
merge
を利用すると「主キーがテーブルに存在するときはその行を更新/update
、存在しないときは挿入/insert
」を実現できることが上記の例から確認できました。
ポイントとしてはusing
節の使い方でしょうか。using
節ではテーブルを指定する必要があるので、上記の例ではダミー表を活用することにより、疑似的にテーブルを実現しています。
なお上記の例はDB2を利用しているため、ダミーのテーブルの名前がsysibm.sysdummy1
になっています。DB2以外を利用する場合は別のダミー表名を指定するなり、from
節を省略するなりして、適宜読み替えてください。