---
title: "MERGE statement"
description: "MERGE INTO is a SQL statement that inserts, updates, or deletes rows in a target table based on how they match rows from a source table, in a single atomic operation."
canonical: "https://motherduck.com/glossary/merge-statement/"
related:
  - title: "INSERT | MotherDuck Docs"
    url: "https://motherduck.com/docs/sql-reference/duckdb-sql-reference/duckdb-statements/insert/"
  - title: "What's New in DuckDB 1.5! | MotherDuck"
    url: "https://motherduck.com/videos/whats-new-duckdb-15/"
  - title: "Replicate PostgreSQL Tables to MotherDuck with dlt | MotherDuck Docs"
    url: "https://motherduck.com/docs/cookbook/dlt-db-replication/"
---

# MERGE statement

> MERGE INTO is a SQL statement that inserts, updates, or deletes rows in a target table based on how they match rows from a source table, in a single atomic operation.

## Overview
`MERGE INTO` (sometimes just `MERGE`) is the SQL-standard statement for synchronizing a target table with a source table or query result, applying different actions depending on whether each source row matches an existing target row:

```sql
MERGE INTO target_table t
USING source_table s
ON t.id = s.id
WHEN MATCHED THEN
  UPDATE SET t.value = s.value
WHEN NOT MATCHED THEN
  INSERT (id, value) VALUES (s.id, s.value);
```

Unlike `INSERT ... ON CONFLICT`, `MERGE` doesn't require a declared primary key or unique constraint — the match condition in the `ON` clause can be any expression. It can also express deletes (`WHEN MATCHED THEN DELETE`) and multiple conditional branches with additional predicates, making it well-suited for slowly changing dimension (SCD) loads and change-data-capture (CDC) pipelines.

<glossary-callout guide="duckdb-cheatsheet-full" />

## DuckDB specifics
DuckDB added `MERGE INTO` support in version 1.4. Its syntax follows the pattern above, with a few DuckDB-specific extensions: a `WHEN NOT MATCHED BY SOURCE` clause to handle target rows absent from the source (e.g., to delete them), and a `RETURNING` clause that reports which action (`merge_action`) was taken per row:

```sql
MERGE INTO people
USING (SELECT 1 AS id, 98000.0 AS salary) updates
  ON updates.id = people.id
WHEN MATCHED THEN UPDATE SET salary = updates.salary
WHEN NOT MATCHED THEN INSERT
RETURNING merge_action, *;
```

DuckDB's `MERGE INTO` also works against Iceberg tables via the DuckDB-Iceberg extension, letting you apply an entire changeset (inserts, updates, and deletes) to an Iceberg table in one statement — useful for CDC-style pipelines writing into a lakehouse table format.