Skip to main content
When building materialized views that refresh periodically, you often need to update existing records rather than simply appending new ones. The 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:

The problem

Consider a view that refreshes monthly with recent activity data. With WRITE_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: Use these aliases in your MERGE ON condition and in the WHEN MATCHED/WHEN NOT MATCHED clauses.

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.
Key points:
  • 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_at column 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) with IS NOT DISTINCT FROM to handle nullable values safely.
Key points:
  • IS NOT DISTINCT FROM treats 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

Common pitfalls

Non-unique match keysIf your MERGE ON condition matches multiple target rows for a single source row, you may see unexpected updates or duplicate inserts. Ensure your match key (or composite key) uniquely identifies records.
Using = on nullable fieldsUsing plain = to compare nullable fields can cause matches to be missed:
MERGE ON only works in CREATE MATERIALIZED VIEWMERGE ON is a clause within the CREATE MATERIALIZED VIEW statement. It cannot be used as a standalone MERGE command in Data Studio. For row-level changes outside a materialized view refresh, use standalone INSERT, UPDATE, or DELETE statements instead.

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