SQL ServerのMERGEステートメントの完全ガイド

SQL ServerのMERGEステートメントは、**1つの操作でデータのINSERT(追加)、UPDATE(更新)、DELETE(削除)**を同時に実行できる強力なSQLコマンドです。

通常、テーブルを更新するときにはINSERT、UPDATE、DELETEをそれぞれ分けて行いますが、MERGEを使うことで、一度のSQLで条件に応じたデータ操作ができるようになります。

例えば、商品管理システムで新しい在庫データが来たときに、既存の商品を更新するか、見つからない商品を新規追加するケースを想像してみてください。

MERGEを使えば、こうした操作を効率的に一括で行うことができます。


MERGEの基本構文

MERGEの基本構文は以下の通りです。

MERGE INTO 対象テーブル AS target
USING 参照テーブル AS source
ON target.キー列 = source.キー列
WHEN MATCHED THEN
    -- マッチした場合の処理
    UPDATE SET target.列名 = source.列名
WHEN NOT MATCHED THEN
    -- マッチしない場合の処理
    INSERT (列名1, 列名2, ...) VALUES (source.列名1, source.列名2, ...)
WHEN NOT MATCHED BY SOURCE THEN
    -- ソースに存在しないデータの処理
    DELETE;

MERGEの使用例

ここでは、2つのテーブルを用いた実際の例を見てみましょう。

  • 対象テーブル(Products):現在の在庫情報を持つテーブル
  • 参照テーブル(NewStock):新しい在庫データを持つテーブル

テーブルの作成

まず、例で使用するテーブルを作成します。

-- Productsテーブルの作成
CREATE TABLE Products (
    ProductID INT PRIMARY KEY,
    ProductName VARCHAR(100),
    Stock INT
);

-- NewStockテーブルの作成
CREATE TABLE NewStock (
    ProductID INT PRIMARY KEY,
    ProductName VARCHAR(100),
    Stock INT
);

サンプルデータの挿入

-- Productsにデータを挿入
INSERT INTO Products (ProductID, ProductName, Stock)
VALUES (1, 'Laptop', 10),
       (2, 'Mouse', 50),
       (3, 'Keyboard', 30);

-- NewStockにデータを挿入
INSERT INTO NewStock (ProductID, ProductName, Stock)
VALUES (1, 'Laptop', 15),  -- 在庫が更新されるべき
       (2, 'Mouse', 50),   -- 変わらない
       (4, 'Monitor', 20); -- 新規追加されるべき

MERGEを使った処理

上記の2つのテーブルを使い、新しい在庫データに基づいてProductsテーブルを更新します。

MERGE INTO Products AS target
USING NewStock AS source
ON target.ProductID = source.ProductID
WHEN MATCHED THEN
    UPDATE SET target.Stock = source.Stock
WHEN NOT MATCHED THEN
    INSERT (ProductID, ProductName, Stock)
    VALUES (source.ProductID, source.ProductName, source.Stock)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE;
  • MATCHEDの場合:同じProductIDがある場合、在庫(Stock)を更新
  • NOT MATCHEDの場合:参照テーブルに存在するが対象テーブルにない場合、商品を新規追加
  • NOT MATCHED BY SOURCEの場合:新しい在庫データに存在しない商品は削除

MERGEのメリットと注意点

メリット

  • コードの簡略化:1つのSQLで複数の操作が可能になる。
  • パフォーマンスの向上:複数のSQL文を実行するより効率的。
  • 管理の容易さ:変更箇所が一箇所にまとまるためメンテナンスが楽。

注意点

  • デッドロック:複数のテーブルにアクセスするため、デッドロックが発生する可能性があります。
  • トリガーの動作:MERGEがトリガーの動作に影響する場合があるため、注意が必要です。
  • NULL処理:条件やデータにNULLが含まれる場合、意図しない結果を生むことがあります。

MERGEを使った演習問題

次の演習では、上記と似たケースを体験します。以下のようなテーブルを用意してください。

演習課題

Employeesテーブル:現在の社員情報を管理するテーブル

CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    EmployeeName VARCHAR(100),
    Department VARCHAR(50)
);

INSERT INTO Employees (EmployeeID, EmployeeName, Department)
VALUES (1, 'Alice', 'HR'),
       (2, 'Bob', 'IT'),
       (3, 'Charlie', 'Finance');

NewEmployeesテーブル:新しい社員データを管理するテーブル

CREATE TABLE NewEmployees (
    EmployeeID INT PRIMARY KEY,
    EmployeeName VARCHAR(100),
    Department VARCHAR(50)
);

INSERT INTO NewEmployees (EmployeeID, EmployeeName, Department)
VALUES (1, 'Alice', 'HR'),         -- 更新されない
       (2, 'Bob', 'Engineering'),  -- 部署が更新されるべき
       (4, 'Dave', 'Marketing');   -- 新規追加されるべき

課題:上記の2つのテーブルを使い、以下の条件でEmployeesテーブルを更新するMERGE文を作成してください。

  • EmployeeIDが一致する場合は部署を更新
  • 一致しない場合は新しい社員を追加
  • 新しい社員データに存在しない社員は削除

演習問題の解答例

以下は演習問題の解答例です。

MERGE INTO Employees AS target
USING NewEmployees AS source
ON target.EmployeeID = source.EmployeeID
WHEN MATCHED THEN
    UPDATE SET target.Department = source.Department
WHEN NOT MATCHED THEN
    INSERT (EmployeeID, EmployeeName, Department)
    VALUES (source.EmployeeID, source.EmployeeName, source.Department)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE;

実行結果

  • Aliceのデータは変更なし。
  • Bobの部署がITからEngineeringに更新されます。
  • Daveが新規追加されます。
  • Charlieは新しいデータに存在しないため削除されます。

まとめ

MERGEステートメントは、複数のテーブル操作を1つのクエリで簡潔に行えるため、SQL Serverで非常に便利な機能です。

ただし、使用する際はデッドロックやNULL処理などの注意点も考慮する必要があります。

今回の演習問題を通じて、MERGEの基礎をしっかりと学ぶことができたでしょう。今後のデータベース操作で、効率的に活用してみてください。