SQL for Writing Data: DDL, DML, Transactions & Upserts
Back to Write-Side SQL for Engineers

MERGE & Upserts: Handling Replays

Merge keys, ON CONFLICT vs MERGE, SCD-1 limits, replay test.

3 minutesInteractive tutorial
๐ŸŽฏ Free Guest Mode: You are learning for free. Sign in to save your completion progress and quiz answers.

Sources resend data. Late events arrive. Your load must converge, not duplicate.

-- Postgres: replay-safe upsert
INSERT INTO dim_customers (customer_id, name, tier)
VALUES (1, 'Acme', 'enterprise')
ON CONFLICT (customer_id) DO UPDATE
SET name = EXCLUDED.name, tier = EXCLUDED.tier;

-- Warehouse (BigQuery/Snowflake): MERGE
MERGE INTO mart_orders AS t
USING stg_orders AS s ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET status = s.status, amount_cents = s.amount_cents
WHEN NOT MATCHED THEN INSERT (order_id, customer_id, ordered_at, amount_cents, status)
VALUES (s.order_id, s.customer_id, s.ordered_at, s.amount_cents, s.status);

Rules

  1. Every incremental load needs a merge key (usually the source PK). No key, no safe replay โ€” fix the key before building the pipeline.
  2. ON CONFLICT DO NOTHING for insert-only streams (events, logs); DO UPDATE for slowly-changing dimensions.
  3. MERGE is SCD-1 in one statement (overwrite latest). SCD-2 history still needs explicit effective-date logic โ€” MERGE alone won't version rows.
  4. Test the replay: run the load twice in staging and diff. Zero new rows on the second run is the acceptance test.

No questions available for this tutorial.