SQL MERGE文でINSERTとUPDATEを一回で行う
テーブルにデータがすでに存在している場合は更新(UPDATE
)、存在していない場合は登録(INSERT
)をしたい場合があると思います。
例えば以下のような場合です。
「社員マスタ」というテーブルがあります。カラムは下記のとおりです。(わかりやすくするため、正規化は考えていません)
社員コード | 社員名 | 年齢 |
---|---|---|
1 | テスト社員1 | 42 |
2 | テスト社員2 | 30 |
3 | テスト社員3 | 20 |
また、以下のような「退職社員マスタ」というテーブルがあります。
社員コード | 社員名 | 年齢 |
---|---|---|
1 | テスト社員1 | 31 |
30歳以上の社員を退職社員マスタに登録したい場合、退職社員マスタのデータが空の場合はselect-insertで紹介したように、SELECT-INSERTで1回で登録することができます。
退職社員マスタにすでにデータあるときは、主キー重複エラーなどを回避するため、存在チェックなどを行う必要が出てきます。
MERGE文
MERGE
文を使えば一回のSQL
で、退職社員マスタにデータが存在しない場合はINSERT
、すでに存在している場合はUPDATE
といった処理を簡単に行うことができます。
MERGE INTO 退職社員マスタ T1 --登録先のデータ
USING (
--登録元のデータ
SELECT
S1.社員コード
,S1.社員名
,S1.年齢
FROM
社員マスタ S1
WHERE
S1.年齢 >= 30
)
ON (
--登録先のデータと登録元のデータを結合
--(登録元のデータが登録先に登録されているかどうかの判定)
T1.社員コード = S1.社員コード
)
WHEN MATCHED THEN
--登録先すでに存在している場合
UPDATE SET
T1.社員名 = S1.社員名
,T1.年齢 = S1.年齢
WHEN NOT MATCHED THEN
--登録先に存在しない場合
INSERT
(社員コード, 社員名, 年齢)
VALUES
(S1.社員コード, S1.社員名, S1.年齢)
社員コード | 社員名 | 年齢 |
---|---|---|
1 | テスト社員1 | 42 |
2 | テスト社員2 | 30 |
テスト社員1はデータが存在するためUPDATE
され、テスト社員2はデータがなかったのでINSERT
されました。
UPDATEにWHERE句を追加
例えば上記のSQL
で「社員名が変更された時だけ年齢を更新したい」という要望があった場合は、UPDATE
の処理にWHERE
句の条件を追加することができます。
--省略
WHEN MATCHED THEN
--登録先すでに存在している場合
UPDATE SET
T1.社員名 = S1.社員名
,T1.年齢 = S1.年齢
--登録元と登録先の社員名が異なる場合(社員名変更された場合)のみUPDATEを行う
WHERE T1.社員名 <> S1.社員名
--省略
MERGE
文を使いこなせればかなりシンプルにSQLを実装することができるようになります。