【PL/SQL】MERGE文の活用法|UPSERT処理を高速かつ安全に実装する方法

【PL/SQL】MERGE文の活用法|UPSERT処理を高速かつ安全に実装する方法 PL/SQL

PL/SQLでデータをINSERTまたはUPDATEする処理は、業務システムで頻繁に登場します。例えば「データが存在すれば更新し、なければ新規挿入する」というロジックは、通称「UPSERT(アップサート)」と呼ばれます。

このような処理を簡潔かつ効率よく記述できるのが、OracleのMERGE文です。本記事では、MERGE文の基本構文と応用例、パフォーマンス面や注意点について解説します。

MERGE文とは?

MERGE文は、1つのSQLでUPDATEまたはINSERTのいずれかを実行できる構文です。複数のSQL文を書く必要がないため、ロック競合や二重登録を防ぎつつ、シンプルに記述できます。

基本構文

MERGE INTO target_table tgt
USING (SELECT :id AS id, :name AS name FROM dual) src
  ON (tgt.id = src.id)
WHEN MATCHED THEN
  UPDATE SET tgt.name = src.name
WHEN NOT MATCHED THEN
  INSERT (id, name) VALUES (src.id, src.name);

この構文は以下の処理を意味します:

  • idが一致するレコードがtarget_tableにあれば、nameを更新
  • 一致しなければ新規に挿入

MERGE文のメリット

  • 処理が1文で完結するため、トランザクション管理がしやすい
  • ロック競合や重複INSERTのリスクが少ない
  • IF文による分岐処理が不要で、可読性が高い
  • パフォーマンスが高い(UPDATE対象とINSERT対象を一括判定)

応用例:複数レコードを一括アップサート

複数行を一括でアップサートする場合は、サブクエリや一時テーブルを使ってデータを渡すことができます。

MERGE INTO employees tgt
USING (
  SELECT 1001 AS emp_id, '田中' AS emp_name FROM dual
  UNION ALL
  SELECT 1002, '佐藤' FROM dual
) src
ON (tgt.emp_id = src.emp_id)
WHEN MATCHED THEN
  UPDATE SET tgt.emp_name = src.emp_name
WHEN NOT MATCHED THEN
  INSERT (emp_id, emp_name) VALUES (src.emp_id, src.emp_name);

このようにして、データの存在確認→更新または挿入という流れを1文で効率的に処理できます。

MERGE文を使う際の注意点

  • ON句の条件が適切でないと、誤ったレコードが更新されるリスクがある
  • NOT MATCHED BY SOURCEによる削除処理など、書き方によっては全削除になる危険がある
  • 対象テーブルにユニーク制約がある場合、MERGE内でのINSERTが失敗する可能性がある

特にON条件の設定ミスは重大なデータ事故につながるため、業務要件に即した厳密な条件設計が求められます。

MERGE文とトランザクション管理

MERGE文は1文で完結するため、トランザクションの境界を明確にできるのも利点の一つです。例えば複数のMERGEを行う場合でも、BEGIN ~ COMMITで囲むことで一括制御が可能です。

BEGIN
  -- MERGE文1
  -- MERGE文2
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
    RAISE;
END;

まとめ:MERGE文はUPSERTの最適解

UPSERT処理が必要な場面では、MERGE文を活用することでSQLの記述量を減らし、トランザクション管理やパフォーマンスも向上します。

ただし、ON条件の精査と更新/挿入対象列の設計には十分な注意が必要です。誤ったデータ更新や意図しない重複を防ぐためにも、事前に検証環境でしっかりとテストを行いましょう。

MERGE文を使いこなせば、PL/SQLにおけるデータ整合性の維持とコードの簡素化を同時に実現できます。