【SQLServer】重複がなければINSERTするSQL【MERGE】

SQLServer

SQLServerで用意されているSQLを用いて、指定した列の値をキーにして重複チェックし、重複するレコードがなければINSERTし、あった場合はINSERTしない、という処理のSQLの紹介です。

LEFT JOINで重複チェックする方法を用いても可能ですが、今回はMERGEを用いることにします。

複数人で開発を行っている場合などはMERGEを使う方法の方がソースを見たときに直観的に何をしているか伝わりやすいと思います。

サンプルの動作確認環境

  • Windows10 64bit
  • SQLServer2017 Express

サンプルSQLの仕様

SQL実行前(青がINSERTされる側のテーブル)
SQL実行後

サンプルSQL

INSERTされるテーブルの準備

テーブル名はT_Tagertとしています。

CREATE TABLE [T_Target](
[id] [int] IDENTITY(1,1) NOT NULL,
[Item1] [nvarchar](max) NULL,
[Item2] [nvarchar](max) NULL,
[Item3] [nvarchar](max) NULL
);
INSERT INTO [T_Target]
           ([Item1]
           ,[Item2]
           ,[Item3])
     VALUES
           ('01',
            '01',
            '01');

重複チェックしINSERTするSQL

Item1、Item2列の組み合わせで重複チェックを行い、重複がなければINSERTを行います。INSERTするデータはUNIONでまとめています。

With InsertData as (
SELECT '01' Item1, '01' Item2, '02' Item3
UNION 
SELECT '01' Item1, '02' Item2, '01' Item3
UNION 
SELECT '02' Item1, '01' Item2, '01' Item3
)
MERGE ST_DB.dbo.T_Target AS TargetData 
USING InsertData 
ON TargetData.Item1 = InsertData.Item1 AND TargetData.Item2 = InsertData.Item2
WHEN NOT MATCHED BY TARGET 
   THEN INSERT (Item1, Item2, Item3)
            VALUES (InsertData.Item1, InsertData.Item2, InsertData.Item3);

補足:MERGEについて

上記ではMERGEで、

T_Target(上記サンプルの更新される側のテーブル)に同じデータが存在しない場合

にどうするかだけを定義しましたが、本来の使い方として

  • T_Targetにだけデータが存在する場合
  • T_Targetに同じデータが存在する場合

それぞれのケースで何をするか定義することも可能です。↓のような構文となります。

MERGE {変更対象テーブル} 
USING {参照テーブル}
ON {存在有無を確認する式}
WHEN MATCHED
   THEN {両方のテーブルに存在する場合の処理}
WHEN NOT MATCHED BY TARGET 
   THEN {変更対象テーブルに存在しない場合の処理}
WHEN NOT MATCHED BY SOURCE
   THEN {参照テーブルに存在しない場合の処理}

ここでは、T_Target2というテーブルを用意し、Item1列、Item2列の組み合わせで重複チェックしたうえで、

  • T_Target2には同じデータが存在しない場合はINSERT
  • T_Target2にだけデータが存在する場合はDELETE
  • T_Target2にも同じデータが存在する場合UPDATE

を行うサンプルSQLを紹介します。

イメージ:SQL実行前の構成
イメージ:SQL実行後

まず、下のSQLを実行してT_Target2テーブルを準備してください。

CREATE TABLE [T_Target2](
[id] [int] IDENTITY(1,1) NOT NULL,
[Item1] [nvarchar](max) NULL,
[Item2] [nvarchar](max) NULL,
[Item3] [nvarchar](max) NULL
);
INSERT INTO [T_Target2]
           ([Item1]
           ,[Item2]
           ,[Item3])
     VALUES
('01','01','01'),
('02','02','01');

以下が上記仕様のSQLとなります。

With InsertData as (
SELECT '01' Item1, '01' Item2, '02' Item3
UNION 
SELECT '01' Item1, '02' Item2, '01' Item3
UNION 
SELECT '02' Item1, '01' Item2, '01' Item3
)
MERGE ST_DB.dbo.T_Target2 AS TargetData 
USING InsertData 
ON TargetData.Item1 = InsertData.Item1 AND TargetData.Item2 = InsertData.Item2
WHEN MATCHED
   THEN UPDATE 
      SET
         TargetData.Item3 = InsertData.Item3
WHEN NOT MATCHED BY TARGET 
   THEN INSERT (Item1, Item2, Item3)
            VALUES (InsertData.Item1, InsertData.Item2, InsertData.Item3)
WHEN NOT MATCHED BY SOURCE
   THEN DELETE;

以上となります。

タイトルとURLをコピーしました