UPSERT (ON CONFLICT)

RoadmapsSQL

Overview

UPSERT is a combination of 'update' and 'insert'. In Postgres, it's written as INSERT ... ON CONFLICT. If a row with the same unique key already exists, instead of throwing an error, the database can either DO NOTHING or DO UPDATE to modify the existing row. When using DO UPDATE, you use the special `EXCLUDED` keyword to reference the values that were proposed for insertion.

It safely handles race conditions where multiple requests might try to create the same record simultaneously, and it simplifies application logic by merging check-and-create into a single database operation.

Where used: incrementing page views, saving drafts, idempotent background jobs

Why learn this

Query walkthrough

INSERT INTO products (id, name, category, price) VALUES (2, 'Mouse V2', 'Electronics', 24.99) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, price = EXCLUDED.price RETURNING id, name, price;

Focus: The conflict on id=2 triggers an update, merging the EXCLUDED.name and EXCLUDED.price into the existing row.

Common mistakes

Glossary

idempotent
An operation that produces the same result no matter how many times it is run.
vulnerable
Exposed to the possibility of being attacked or harmed; in code, a weakness that can cause bugs or errors.
constitutes
To make up, form, or be considered as something, like defining what counts as a duplicate record.

Recall questions

Understanding checks

Assume a customer with id = 1 already exists. What rows does this query return (assuming 'id' is a primary key)?

id: 1, name: 'Alice V2'

Customer id 1 already exists, causing a conflict. The DO UPDATE clause triggers, updating the name to 'Alice V2'.

Assume a product with id = 1 already exists. What rows does this query return?

(No rows)

Product id 1 exists. DO NOTHING silently ignores the insert, and since no row was inserted or updated, RETURNING yields nothing.

Practice tasks

Upsert an employee salary

Given this starter code, modify it to update the employee's salary to the new value if the employee id already exists.

Challenge

Upsert an order

Write an upsert query that tries to insert order id 8 for customer 2 on '2023-08-01' with status 'shipped'. If order id 8 already exists, update its status to 'shipped'. Return the id and status.

Continue learning

Previous: INSERT & Returning

Previous: Constraints & defaults

Return to SQL Roadmap