MERGE/UPSERT example in PostgreSQL using CTE
Introduction
PostgreSQL doesn’t provide direct MERGE or UPSERT commands. But similar results can by achieved using CTE (Common Table Expressions).
I’ll use following table to illustrate this solution:
INSERT not existing rows
I’ll now try to insert some new records (one new and one already existing name):
This yields:
name | age
-------+-----
Carol | 37
(1 row)
INSERT 0 1
And after issuing SELECT * FROM person;
we’ll get:
name | age
-------+-----
John | 31
Jane | 24
Carol | 37
(3 rows)
In this WITH
query I defined to_be_inserted
as static collection of rows to be inserted, existing
collection as names that are present in to_be_inserted
and exists in person
table and then we use both these collections to perform conditional INSERT
. All in one query.
Updating exitsing rows and inserting new ones
Now I’ll try to update two records and insert non-existing one:
And after issuing SELECT * FROM person;
again we’ll get:
name | age
-------+-----
Jane | 24
John | 46
Carol | 23
Edgar | 18
Here I defined to_be_upserted
static collection and used it to define updated
collection which returns only updated (i.e. existing) rows and then I issue INSERT
query to insert non-existent rows.
Using CTEs with data-modifying statements can save some round trips between database and application.