JSONからSQL UPSERT(INSERT ON CONFLICT)を生成する

INSERT ON CONFLICT(PostgreSQL)とON DUPLICATE KEY UPDATE(MySQL)を使用してJSONデータからUPSERT文を生成する方法を学びます。競合ターゲット、更新式、マージパターンを解説します。

Advanced Patterns

詳細な説明

JSONからSQL UPSERTへ

UPSERT(INSERTまたはUPDATE)は、行が存在しない場合は新規挿入し、競合が検出された場合は既存行を更新します。JSONからの冪等なデータインポートに不可欠です。

JSONの例

[
  { "id": 1, "name": "Alice", "email": "alice@new.com", "score": 95 },
  { "id": 2, "name": "Bob", "email": "bob@example.com", "score": 87 }
]

PostgreSQL(ON CONFLICT)

INSERT INTO users (id, name, email, score) VALUES
  (1, 'Alice', 'alice@new.com', 95),
  (2, 'Bob', 'bob@example.com', 87)
ON CONFLICT (id) DO UPDATE SET
  name = EXCLUDED.name,
  email = EXCLUDED.email,
  score = EXCLUDED.score;

MySQL(ON DUPLICATE KEY UPDATE)

INSERT INTO users (id, name, email, score) VALUES
  (1, 'Alice', 'alice@new.com', 95),
  (2, 'Bob', 'bob@example.com', 87)
ON DUPLICATE KEY UPDATE
  name = VALUES(name),
  email = VALUES(email),
  score = VALUES(score);

SQL Server(MERGE)

MERGE INTO users AS target
USING (VALUES
  (1, 'Alice', 'alice@new.com', 95),
  (2, 'Bob', 'bob@example.com', 87)
) AS source (id, name, email, score)
ON target.id = source.id
WHEN MATCHED THEN UPDATE SET
  name = source.name,
  email = source.email,
  score = source.score
WHEN NOT MATCHED THEN INSERT (id, name, email, score)
  VALUES (source.id, source.name, source.email, source.score);

競合ターゲットのオプション

競合ターゲット ユースケース
主キー(id 標準的な行識別
ユニーク制約(email ビジネスキーによる重複排除
複合キー(user_id, date 時系列データの重複排除

部分更新

競合時に特定のカラムのみを更新したい場合:

ON CONFLICT (id) DO UPDATE SET
  email = EXCLUDED.email,
  score = GREATEST(users.score, EXCLUDED.score);
-- 新しい値が大きい場合のみscoreを更新

DO NOTHING

重複を更新せずにスキップしたい場合:

INSERT INTO users (id, name, email)
VALUES (1, 'Alice', 'alice@example.com')
ON CONFLICT (id) DO NOTHING;

ユースケース

既に格納済みのレコードを返す可能性のあるJSON API(Webhookリプレイや定期的なフルシンクなど)からデータを同期する際、UPSERTにより重複キーエラーなしで冪等なインポートが保証されます。これは信頼性の高いデータ同期パイプラインの構築に不可欠です。

試してみる — JSON to SQL

フルツールを開く