SQL Tutorial
SQL Clauses / Operators
SQL-Injection
SQL Functions
SQL Queries
PL/SQL
MySQL
SQL Server
Misc
The MERGE
statement, often called "upsert" (a blend of update and insert), is used to either insert new records or update existing ones depending on whether a particular condition (usually a match on a primary key or unique constraint) is met. It's especially useful when you're working with data synchronization scenarios.
The MERGE
statement is supported by several RDBMS like Oracle, SQL Server, and DB2. However, not every database supports the MERGE
statement, and the exact syntax might differ slightly.
Here's a general overview of the MERGE
statement:
MERGE INTO target_table USING source_table ON (condition) -- Often a condition to match records, e.g., target_table.id = source_table.id WHEN MATCHED THEN UPDATE SET column1 = value1, column2 = value2, ... WHEN NOT MATCHED THEN INSERT (column1, column2, ... ) VALUES (value1, value2, ...);
Imagine you have a target table employees
and a source table new_data
. You want to update the records in employees
based on the matching id
from new_data
or insert the data if there isn't a match:
MERGE INTO employees AS tgt USING new_data AS src ON (tgt.id = src.id) WHEN MATCHED THEN UPDATE SET tgt.name = src.name, tgt.salary = src.salary WHEN NOT MATCHED THEN INSERT (id, name, salary) VALUES (src.id, src.name, src.salary);
This statement will go through each record in new_data
:
id
in new_data
matches an id
in employees
, the corresponding record in employees
will be updated.id
in new_data
doesn't have a match in employees
, a new record will be inserted into employees
.Some databases might support additional clauses, such as WHEN NOT MATCHED BY SOURCE
or WHEN NOT MATCHED BY TARGET
, providing more flexibility.
Since the MERGE
statement can potentially modify multiple rows in different ways, be cautious with triggers that might fire as a result of these changes.
As always, it's a good idea to test the MERGE
statement in a controlled environment before using it on production data.
Databases like PostgreSQL and MySQL don't natively support the MERGE
statement but offer their mechanisms for upsert operations, like INSERT ... ON DUPLICATE KEY UPDATE
for MySQL or INSERT ... ON CONFLICT
for PostgreSQL.
How to use MERGE in SQL:
MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.column1 = source.column1 WHEN NOT MATCHED THEN INSERT (id, column1) VALUES (source.id, source.column1);
Merging data from source to target in SQL:
MERGE INTO target_table AS target USING source_table AS source ON target.customer_id = source.customer_id WHEN MATCHED THEN UPDATE SET target.name = source.name WHEN NOT MATCHED THEN INSERT (customer_id, name) VALUES (source.customer_id, source.name);
Handling conflicts with the MERGE statement:
MERGE INTO target_table AS target USING source_table AS source ON target.employee_id = source.employee_id WHEN MATCHED AND source.salary > target.salary THEN UPDATE SET target.salary = source.salary;
Performing upserts with the SQL MERGE statement:
MERGE INTO target_table AS target USING source_table AS source ON target.product_id = source.product_id WHEN MATCHED THEN UPDATE SET target.price = source.price WHEN NOT MATCHED THEN INSERT (product_id, price) VALUES (source.product_id, source.price);
Comparing MERGE with INSERT and UPDATE in SQL:
-- Using MERGE MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.column1 = source.column1 WHEN NOT MATCHED THEN INSERT (id, column1) VALUES (source.id, source.column1); -- Equivalent using separate INSERT and UPDATE UPDATE target_table SET column1 = (SELECT column1 FROM source_table WHERE target_table.id = source_table.id) WHERE EXISTS (SELECT 1 FROM source_table WHERE target_table.id = source_table.id); INSERT INTO target_table (id, column1) SELECT id, column1 FROM source_table WHERE NOT EXISTS (SELECT 1 FROM target_table WHERE target_table.id = source_table.id);
Dynamic value for MERGE in SQL:
DECLARE @source_value INT = 100; MERGE INTO target_table AS target USING (VALUES (@source_value)) AS source (column1) ON target.id = source.column1 WHEN MATCHED THEN UPDATE SET target.column2 = 'Updated' WHEN NOT MATCHED THEN INSERT (id, column2) VALUES (source.column1, 'Inserted');
Using conditions in the SQL MERGE statement:
MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED AND source.status = 'Active' THEN UPDATE SET target.column1 = source.column1 WHEN NOT MATCHED AND source.status = 'Active' THEN INSERT (id, column1) VALUES (source.id, source.column1);
Logging changes during a MERGE operation in SQL:
CREATE TABLE merge_log ( action VARCHAR(10), id INT, column1 VARCHAR(255), log_timestamp DATETIME ); MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.column1 = source.column1 OUTPUT 'UPDATE', inserted.id, inserted.column1, GETDATE() INTO merge_log WHEN NOT MATCHED THEN INSERT (id, column1) VALUES (source.id, source.column1) OUTPUT 'INSERT', inserted.id, inserted.column1, GETDATE() INTO merge_log;
Merging data in SQL tables with MERGE:
MERGE INTO employees AS target USING employees_backup AS source ON target.employee_id = source.employee_id WHEN MATCHED THEN UPDATE SET target.salary = source.salary WHEN NOT MATCHED THEN INSERT (employee_id, salary) VALUES (source.employee_id, source.salary);