I have this table:
CREATE TABLE myTable ( a VARCHAR(32), b VARCHAR(32) DEFAULT NULL, c VARCHAR(32) DEFAULT NULL, PRIMARY KEY (a) );
and this “UPSERT” type query:
INSERT INTO myTable ( a, b, c) VALUES ($1, $2, $3) ON CONFLICT (a) DO UPDATE SET b = $2, c = $3, RETURNING a, b, c ;
This works as expected. If I first insert (json for notational convenience):
{a:"a", b:"b", c:"c"}
then I can update it with params like this:
{a:"a", b:"x", c:"y"}
And I get the expected result– the {a:”a”} record has updated b
and c
columns.
But I would like to also be able to do this:
{a:"a", c:"Q"}
and update the c
column while leaving column b
intact.
Of course, I need some kind of expression on the right hand side, but I don’t know what that is. My intuition is something like this (SQL pseudocode):
... DO UPDATE SET b = ($2 | b) c = ($3 | c) ...
What’s the right syntax here? Or, is there a completely different method I should be using?
Advertisement
Answer
You can use COALESCE()
. The idea is to pass a NULL
value to one of the parameters, and then you can do:
INSERT INTO myTable (a, b, c) VALUES ($1, $2, $3) DO UPDATE SET b = COALESCE(EXCLUDED.b, b) c = COALESCE(EXCLUDED.c, c)
When a record already exists with a = $1
and $1
or $2
are given a null
value and , then only the non-null
value is written.
The downside is that this query will not be able to assign a null
value to an already-existing record.
Side note: this uses pseudo-table EXCLUDED
rather than repeating the parameters.