レコードが存在しない場合はレコードを挿入し、レコードが存在する場合はレコードを更新する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テーブル
id | name | category | price | point |
---|
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を実行すると下図の状態になります。レコードがなかったため、レコードが挿入されました。
id | name | category | price | point |
1 | Penguin | BOX | 230 | 10 |
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の値が更新されています。
id | name | category | price | point |
1 | Penguin | BOX | 540 | 22 |
補足
値が固定の場合は、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やデータベースの記事なども担当。