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により重複キーエラーなしで冪等なインポートが保証されます。これは信頼性の高いデータ同期パイプラインの構築に不可欠です。