Advertisement Space

Combining INSERT and UPDATE with MERGE

The MERGE statement (also known as "upsert") lets you insert new rows and update existing ones in a single, atomic operation. It's much cleaner and faster than writing separate INSERT and UPDATE statements with existence checks.

Recipe #1 - Basic MERGE statement

Suppose you have a staging table with new data that needs to be merged into a target table:

MERGE INTO employees tgt
USING employees_staging src
ON (tgt.employee_id = src.employee_id)
WHEN MATCHED THEN
  UPDATE SET
    tgt.salary     = src.salary,
    tgt.department = src.department,
    tgt.updated_at = SYSDATE
WHEN NOT MATCHED THEN
  INSERT (employee_id, name, salary, department, created_at)
  VALUES (src.employee_id, src.name, src.salary, src.department, SYSDATE);

Recipe #2 - MERGE with DELETE clause

Since Oracle 10g, you can also delete rows as part of a MERGE. The DELETE only affects rows that were updated by the MATCHED clause:

MERGE INTO products tgt
USING product_updates src
ON (tgt.product_id = src.product_id)
WHEN MATCHED THEN
  UPDATE SET
    tgt.price  = src.price,
    tgt.status = src.status
  DELETE WHERE tgt.status = 'DISCONTINUED'
WHEN NOT MATCHED THEN
  INSERT (product_id, name, price, status)
  VALUES (src.product_id, src.name, src.price, src.status);

Recipe #3 - MERGE with a subquery

You don't need a staging table — you can use a subquery or even a VALUES clause as the source:

MERGE INTO config_settings tgt
USING (
  SELECT 'MAX_RETRIES' AS key, '5' AS value FROM DUAL
) src
ON (tgt.key = src.key)
WHEN MATCHED THEN
  UPDATE SET tgt.value = src.value
WHEN NOT MATCHED THEN
  INSERT (key, value) VALUES (src.key, src.value);

MERGE is one of the most powerful SQL statements in Oracle and should be your go-to whenever you need conditional insert/update logic.