blob: 90731105d491c358026d7b2200e5d016bd9a9367 [file] [view]
---
layout: global
title: MERGE INTO
displayTitle: MERGE INTO
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
### Description
The `MERGE INTO` statement merges a source table or query into a target table. Rows of the
target table are matched against the source using a merge condition. Target rows are then
updated or deleted, and new rows are inserted from the source, according to the clauses that
apply. All of these row-level changes are performed as a single atomic operation.
`MERGE INTO` is supported on tables backed by
[Data Source V2](sql-data-sources-v2.html#row-level-dml) connectors that support row-level operations.
### Syntax
```sql
MERGE INTO target_table [ [ AS ] target_alias ]
USING { source_table | ( source_query ) } [ [ AS ] source_alias ]
ON merge_condition
[ WHEN MATCHED [ AND matched_condition ] THEN matched_action ] [ ... ]
[ WHEN NOT MATCHED [ BY TARGET ] [ AND not_matched_condition ] THEN not_matched_action ] [ ... ]
[ WHEN NOT MATCHED BY SOURCE [ AND not_matched_by_source_condition ] THEN not_matched_by_source_action ] [ ... ]
matched_action
{ DELETE | UPDATE SET * | UPDATE SET { column = value } [ , ... ] }
not_matched_action
{ INSERT * | INSERT ( column [ , ... ] ) VALUES ( value [ , ... ] ) }
not_matched_by_source_action
{ DELETE | UPDATE SET { column = value } [ , ... ] }
```
### Parameters
* **target_table**
Specifies the table to be merged into, which may be optionally qualified with a database name.
An optional alias may be provided with or without the `AS` keyword.
**Syntax:** `[ database_name. ] table_name [ [ AS ] alias ]`
* **source_table** / **source_query**
The source of the merge, specified either as a table or as a parenthesized query. An optional
alias may be provided with or without the `AS` keyword.
* **merge_condition**
A boolean expression, introduced by the `ON` keyword, that determines how rows from the source
match rows in the target. It controls which `WHEN` clauses apply to each row.
* **WHEN MATCHED [ AND matched_condition ] THEN matched_action**
Applies to rows that exist in both the source and the target (according to `merge_condition`).
The optional `matched_condition` further restricts which matched rows the clause applies to.
The `matched_condition` and the `matched_action` values can reference columns of both the
target and the source tables.
The `matched_action` can be one of:
- `DELETE`: deletes the matched target row.
- `UPDATE SET *`: updates the matched target row with all source columns, matched by name.
- `UPDATE SET column = value [ , ... ]`: updates the listed target columns with the given values.
* **WHEN NOT MATCHED [ BY TARGET ] [ AND not_matched_condition ] THEN not_matched_action**
Applies to source rows that have no matching row in the target. `BY TARGET` is optional and is
the default interpretation of `WHEN NOT MATCHED`. The optional `not_matched_condition` further
restricts which unmatched source rows the clause applies to. The `not_matched_condition` and the
`not_matched_action` values can reference columns of the source table only.
The `not_matched_action` can be one of:
- `INSERT *`: inserts a new target row using all source columns, matched by name.
- `INSERT ( column [ , ... ] ) VALUES ( value [ , ... ] )`: inserts a new target row, assigning
the given values to the listed columns.
* **WHEN NOT MATCHED BY SOURCE [ AND not_matched_by_source_condition ] THEN not_matched_by_source_action**
Applies to target rows that have no matching row in the source. The optional
`not_matched_by_source_condition` further restricts which such target rows the clause applies to.
The `not_matched_by_source_condition` and the `not_matched_by_source_action` values can reference
columns of the target table only.
The `not_matched_by_source_action` can be one of:
- `DELETE`: deletes the unmatched target row.
- `UPDATE SET column = value [ , ... ]`: updates the listed target columns with the given values.
**Note:**
- A `MERGE INTO` statement must contain at least one `WHEN` clause.
- Multiple clauses of the same type may be specified. For a given row, the clauses of the relevant
type are evaluated in the order they are written, and the first clause whose condition is satisfied
is applied. When multiple clauses of the same type are specified, only the last one may omit its
`AND` condition.
- If a single target row matches more than one source row, the statement fails with a
`MERGE_CARDINALITY_VIOLATION` error, since the row would otherwise be updated or deleted more than
once. This check is skipped when there are no `WHEN MATCHED` clauses, or when the only `WHEN MATCHED`
action is an unconditional `DELETE`, because in those cases the outcome does not depend on the number
of matching source rows.
### Examples
The following examples assume that the `target` and `source` tables have already been created and
populated as shown below. Each example starts from this initial state.
```sql
SELECT * FROM target;
+--+------+-------+
|pk|salary| dep|
+--+------+-------+
| 1| 300| hr|
| 2| 160| eng|
| 5| 100|finance|
+--+------+-------+
SELECT * FROM source;
+--+------+-----+
|pk|salary| dep|
+--+------+-----+
| 1| 350| hr|
| 2| 200| eng|
| 3| 120|sales|
+--+------+-----+
```
#### Update Matched Rows and Insert New Rows
```sql
MERGE INTO target t
USING source s
ON t.pk = s.pk
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
SELECT * FROM target;
+--+------+-------+
|pk|salary| dep|
+--+------+-------+
| 1| 350| hr|
| 2| 200| eng|
| 3| 120| sales|
| 5| 100|finance|
+--+------+-------+
```
#### Conditional Delete, Update, and Insert
```sql
-- Delete matched rows whose source salary exceeds 300, update the remaining matched rows,
-- and insert source rows that do not match any target row.
MERGE INTO target t
USING source s
ON t.pk = s.pk
WHEN MATCHED AND s.salary > 300 THEN DELETE
WHEN MATCHED THEN UPDATE SET salary = s.salary
WHEN NOT MATCHED THEN INSERT (pk, salary, dep) VALUES (s.pk, s.salary, s.dep);
SELECT * FROM target;
+--+------+-------+
|pk|salary| dep|
+--+------+-------+
| 2| 200| eng|
| 3| 120| sales|
| 5| 100|finance|
+--+------+-------+
```
#### Delete Target Rows Not Present in the Source
```sql
MERGE INTO target t
USING source s
ON t.pk = s.pk
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
WHEN NOT MATCHED BY SOURCE THEN DELETE;
SELECT * FROM target;
+--+------+-----+
|pk|salary| dep|
+--+------+-----+
| 1| 350| hr|
| 2| 200| eng|
| 3| 120|sales|
+--+------+-----+
```
#### Update Target Rows Not Present in the Source
```sql
MERGE INTO target t
USING source s
ON t.pk = s.pk
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET dep = 'unassigned';
SELECT * FROM target;
+--+------+----------+
|pk|salary| dep|
+--+------+----------+
| 1| 300| hr|
| 2| 160| eng|
| 5| 100|unassigned|
+--+------+----------+
```
### Related Statements
* [INSERT TABLE statement](sql-ref-syntax-dml-insert-table.html)
* [SELECT statement](sql-ref-syntax-qry-select.html)