Skip to main content
TutorialApplies to: Unified engine deployments
Choose one source row per key, match composite keys, and handle NULL keys explicitly. Star actions map columns by name, rather than by their position in the SELECT list. Each required target field needs one matching source field. Prepare one intended incoming row per business key before applying updates. ROW_NUMBER chooses a row only when its ordering defines a clear winner. Here version orders changes, and event_id breaks equal-version ties under an explicit example contract.

Before you start

You need a writable Iceberg catalog with namespace creation, table creation, and MERGE support. These examples create format-v2 tables in a private namespace. They use inline data and do not need an external sample dataset. Choose an unused namespace. The examples use learn_merge_05. Replace it everywhere if it already exists. In Workbench, select your writable catalog before running any SQL. Keep that catalog selected throughout the lesson. Opening an example does not execute it.

Set up the namespace

Run this setup once:
Each example creates a separate table. Run an example’s setup once. To start it again, remove only that example’s table first, using the cleanup section. Scripts execute as separate operations; they are not a multi-statement transaction.

1. Map star actions by column name

Start with these target rows:
Apply the incoming source below:
Check all rows:
Expect these exact rows, in any display order: The source lists its columns in a different order. Customer 2 still receives the correct values because the star actions resolve columns by name. Extra source columns are not a schema-evolution request.

2. Choose one incoming row per key with an explicit tie-break

Start with these target rows:
Apply the incoming source below:
Check all rows:
Expect these exact rows, in any display order:

3. Match by customer ID and region

Start with these target rows:
Apply the incoming source below:
Check all rows:
Expect these exact rows, in any display order:

4. Observe how equality treats NULL keys

Start with these target rows:
Apply the incoming source below:
Check all rows:
Expect these exact rows, in any display order: SQL equality does not treat two NULL keys as equal. The incoming NULL-key row is inserted. A NULL key is often better rejected before the merge.

5. Use an explicit null-safe match when NULL is a valid key

Start with these target rows:
Apply the incoming source below:
Check all rows:
Expect these exact rows, in any display order: The <=> operator treats two NULL values as a match here. Use this only when the data contract defines NULL as a valid matching key.

Change one thing

Start the relevant example again from its original target rows. Drop only that example table, rerun its CREATE TABLE and INSERT statements, then apply the changed MERGE. Keep the lesson namespace. In the deduplication example, change event 11 to version 5. The winning row should have name Latest, balance 260, and version 5. Keep the explicit tie-break rule.

Check the result

Compare every row and field with the expected tables, including unchanged customers and the number of copies of each key. A Succeeded status alone is not the result check. Wait for confirmed publication before reading the target.

Clean up

Remove only the private tables created by this lesson:

Continue

Make repeated MERGE batches predictable or review the MERGE SQL reference.
Last modified on November 4, 2026