MERGE ON clause lets you match incoming rows against existing data and decide whether to update or insert—avoiding duplicates while keeping data fresh.
Prerequisites
Before using MERGE ON, you should have:- Familiarity with materialized views
- Understanding of write modes (append vs overwrite)
- A dataset with stable keys suitable for matching
The problem
Consider a view that refreshes monthly with recent activity data. WithWRITE_MODE = 'overwrite', each refresh replaces all data—losing historical records. With WRITE_MODE = 'append', each refresh adds new rows—but if the same record appears in multiple refreshes, you get duplicates.
MERGE ON solves this by matching rows between the query result and existing view data, then updating matches and inserting non-matches.
How MERGE ON works
MERGE ON compares each row from your query (the source) against existing rows in the materialized view (the target). Based on the match condition, it either updates the existing row or inserts a new one.Source and target aliases
NQL automatically generates two aliases for use in MERGE ON clauses:| Alias | Description |
|---|---|
source | References columns from the incoming query result |
target | References columns from the existing materialized view |
Use case 1: Incremental upsert with time-bounded matching
This example maintains an audience feed that refreshes monthly. The MERGE ON condition restricts updates to rows considered “fresh” (modified within the last 20 days), which can help respect license refresh windows or avoid stale overwrites.- The time-bounded condition (
target.last_modified_at > CURRENT_TIMESTAMP - INTERVAL '20' DAY) is optional but useful for limiting which rows are considered for updates WRITE_MODE = 'append'is required for incremental merge semantics- The
last_modified_atcolumn tracks when each row was last updated
Use case 2: Enrichment with composite keys
This example enriches internal user data with geographic information from Rosetta Stone. It uses a composite key (user_id + sha256) withIS NOT DISTINCT FROM to handle nullable values safely.
IS NOT DISTINCT FROMtreats two NULL values as equal, unlike=which returns NULL when comparing NULLs- Composite keys work well when no single column uniquely identifies a record
- The enriched columns (country_code, region) update on match while the key columns remain stable
Best practices
| Practice | Why |
|---|---|
| Use a stable, unique key for matching | Non-unique or changing keys cause repeated inserts or updates to wrong rows |
Use IS NOT DISTINCT FROM for nullable fields | Plain = on nullable fields can misclassify matches (NULL = NULL returns NULL, not true) |
| Consider time-bounded conditions | Scoping to recent data respects license windows and improves performance |
Always use WRITE_MODE = 'append' | Required for incremental merge semantics; overwrite mode replaces all data |
| Keep MERGE ON conditions minimal | Overly broad conditions cause frequent rewrites; scope to the minimum key set needed |
Common pitfalls
Related content
Materialized View Syntax
Complete reference for MERGE ON and other options
Incremental View Maintenance
How NQL optimizes refreshes for large datasets
Materialized Views
When and why to use materialized views
Creating Materialized Views
Basic guide to creating materialized views

