SQL Server2008からMergeでInsertとUpdateを共通ロジックでできるようになりました。
declare @tab table
(
id int unique not null,
name nvarchar(4000)
)
insert into @tab values (1,'')
insert into @tab values (2,'')
insert into @tab values (3,'')
insert into @tab values (4,'')
insert into @tab values (5,'')
insert into @tab values (6,'')
insert into @tab values (7,'')
insert into @tab values (8,'')
こんなテスト用のテーブルに8っていうレコードを追加か更新します。
insert into @tab values(8,'a')
で、すでに8がある場合には更新失敗しますよね?
メッセージ 2627、レベル 14、状態 1、行 15
制約 'UQ__#68487DD__3213E83E6A30C649' の UNIQUE KEY 違反。オブジェクト 'dbo.@tab' には重複したキーを挿入できません。重複するキー値は (8) です。
で、この8って言うキーがある場合には、nameをupdateしたいんだって言う場合ありますよね。
たとえばー、ある機械の最新の情報を管理しているので、どんどんupdateする。でも新しい機械の場合には自動でレコードinsertして欲しいとか。
その場合SQLServer2005のBeginTryが使える場合には以下のような感じで実装します。(ほかにもトリガで解決したりします)
begin try
insert into @tab values(8,'a')
end try
begin catch
if @@ERROR = 2627
begin
update @tab set name='a' where id=8
end
else
begin
RAISERROR (1,1,1)
end
end catch
a まぁ8とか’a’が2カ所にあるとかは変数とかパラメーターで解決出来るとして、エラーを発生させてっていう手順はあまり美しくないですね。
merge into @tab as target
using(values (8,'a') )as source (id,name)
on target.id = source.id
when matched then
update set target.name = source.name
when not matched by target then
insert values (id,name);
新しいMerge構文を使うとこのように書けます。
ちょっとややこしいので、絵を
mergeのusingで値を決めてそのあとの()で仮の変数名みたいに名前を付ける。
onで、対象のテーブルとマッチさせる(where)
when matched で、アップデート文のSet部分だけ
when not matchedでインサートのvaluesの部分だけ書く
構文が複雑で覚えられそうにありません。
まぁそれを理解するために書いたんですけどね。