目次

レコードが存在しない場合はレコードを挿入し、レコードが存在する場合はレコードを更新するSQL - MERGE 文の利用 (SQLServerでのUPSERT文の利用)

Transact SQLでレコードが存在しない場合はInsertしてレコードを追加し、レコードが存在していればそのレコードを更新したいことがあります。
従来の方法では、select文で条件に合致するレコードがあるか検索し、検索結果があればそのレコードを更新し、なければレコードを追加する方法で処理できますが、 実行するSQL文を減らし動作を高速化する方法としてMERGE文を利用できます。
この記事ではMERGE文を利用したレコードの追加、更新を紹介します。

概要

MERGE文を利用すると、条件に一致した場合とそうでない場合の処理を記述できます。

書式

以下の書式となります
MERGE INTO (テーブル名) AS (エイリアス名)
USING (ソース元の式)
ON (条件)
WHEN MATCHED THEN
UPDATE SET (列名)=(値), ....
WHEN NOT MATCHED THEN
INSERT ((列名), ...) VALUES ((値), ...);
注意
MERGE文は末尾が";"で終了する必要がありますので注意してください。

MERGE文の例を紹介します。

テーブル

下記のテーブルがある場合を想定します。

Pointテーブル
idnamecategorypricepoint

SQL1

以下のSQLを実行します。
merge into TestTable as A
using (select 'Penguin' as name , 'BOX' as category, 230 as price, 10 as point) as B
on (a.name = B.name)
when matched then
update set category=B.category, price=B.price, point=B.point
when not matched then 
insert (name, category, price, point) values (B.name, B.category, B.price, B.point);

実行結果1

SQLを実行すると下図の状態になります。レコードがなかったため、レコードが挿入されました。
idnamecategorypricepoint
1PenguinBOX23010

SQL2

続いて以下のSQLを実行します。
nameが'Penguin'で既に同じレコードがあるため、レコードを追加ではなく更新する処理になります。
merge into TestTable as A
using (select 'Penguin' as name , 'BOX' as category, 540 as price, 22 as point) as B
on (A.name = B.name)
when matched then
update set category=B.category, price=B.price, point=B.point
when not matched then 
insert (name, category, price, point) values (B.name, B.category, B.price, B.point);

解説

ON節で (A.name=B.name)となっているため、nameが一致していれば when matched then 節が実行され、update処理になります。一致していない場合は、when not matched then 節が実行されinsert処理になります。

実行結果2

nameが'Penguin'で既にあるレコードと一致しているため、レコードの更新処理が実行されました。price, pointの値が更新されています。
idnamecategorypricepoint
1PenguinBOX54022

補足

値が固定の場合は、using 節に何も指定せず、when matched thenやwhen not matched then 節に直接値を記述するSQLでも動作します。ただし、値を2か所に記述する必要があるため、先に紹介した using 節内に記述するほうがシンプルでミスも減ります。
merge into TestTable as A
using (select null as n) as B
on (a.name = 'Penguin')
when matched then
update set category='BOX', price=120, point=10
when not matched then 
insert (name, category, price, point) values ('Penguin', 'BOX', 120, 10);

著者
iPentec.com の代表。ハードウェア、サーバー投資、管理などを担当。
Office 365やデータベースの記事なども担当。
掲載日: 2014-11-06
iPentec all rights reserverd.