PostgreSQL lets you either add or modify a record within a table depending on whether the record already exists. This is commonly known as an
"upsert" operation
(a portmanteau of "insert" and "update").
The actual implementation within PostgreSQL uses the
INSERT
command with a special
ON CONFLICT
clause to specify what to do if the record already exists within the table. You can specify whether you want the record to be updated if it's found in the table already or silently skipped.
How to use the
INSERT...ON CONFLICT
construct
The basic syntax for the insert or update operation looks like this:
INSERTINTO my_table (column1, column2)
VALUES
(value1, value2),
(value3, value4),
(value5, value6),
(value7, value8)
ON CONFLICT <target><action>;
In this context, the
<target>
specifies what conflict you want to define a policy for. This can be any of these:
The name of a specific column or columns:
(column1)
The name of a unique constraint:
ON CONSTRAINT <constraint_name>
The companion
<action>
item will define what PostgreSQL should do if a conflict arises. The
<action>
specified can be one of the following:
DO NOTHING
: Tells PostgreSQL to leave the conflicting record as-is. In essence, this action makes no changes, but suppresses the error that would normally occur if you tried to insert a row that violates a condition.
DO UPDATE
: This tells PostgreSQL that you want to update the row that is already in the table. The syntax for the update mirrors that of the normal
UPDATE
command.
When
DO UPDATE
is specified, a special virtual table called
EXCLUDED
is available for use within the
UPDATE
clause. The table contains the values suggested in the original
INSERT
command (that conflicted with the existing table values).
Note:
If you are connecting to your database with
Prisma Client
, you can perform upsert operations using the dedicated
upsert operation
.
Using the
DO NOTHING
action
For our examples, suppose that we have a table called
director
.
CREATETABLE director (
id SERIALPRIMARYKEY,
name TEXTNOTNULL,
latest_film TEXT
);
INSERTINTO director (name)
VALUES
('frank'),
('bob'),
('sue');
Let's take a look at how PostgreSQL normally handles an insertion where a proposed row conflicts with existing data. Assuming there's already a director with an
id
of 3, PostgreSQL throws an error:
INSERTINTO director (id, name)
VALUES
(3,'susan'),
(4,'delores');
ERROR: duplicate key value violates unique constraint "director_pkey"
DETAIL: Key (id)=(3) already exists.
In this case, neither of the proposed records were added, even if only the first one had a conflict. If we want to continue adding any rows that do not have a conflict, we can use a
ON CONFLICT DO NOTHING
clause.
Here, we tell PostgreSQL to move on if a conflict occurs and continue processing the other rows:
INSERTINTO director (id, name)
VALUES
(3,'susan'),
(4,'delores')
ON CONFLICT (id)DO NOTHING;
INSERT 0 1
If you query the table, it will show that the second record was added even though the first one conflicted with one of the existing records: