snippetsqlModerate
How to get the ID of the conflicting row in upsert?
Viewed 0 times
theconflictingupsertgethowrow
Problem
I have a table
I assumed I could just use
But this returns an empty result set, if the tag with the name "foo" already exists.
I then changed the query to use a noop
This works as intended, but it is somewhat confusing, because I'm just setting the name to the already existing value.
Is this the way to go about this problem or is there a simpler approach I'm missing?
tag with 2 columns: id (uuid) and name (text). I now want to insert a new tag into the table, but if the tag already exists, I want to simply get the id of the existing record.I assumed I could just use
ON CONFLICT DO NOTHING in combination with RETURNING "id":INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT DO NOTHING
RETURNING "id";But this returns an empty result set, if the tag with the name "foo" already exists.
I then changed the query to use a noop
DO UPDATE clause:INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT ("name") DO UPDATE SET "name" = 'foo'
RETURNING "id";This works as intended, but it is somewhat confusing, because I'm just setting the name to the already existing value.
Is this the way to go about this problem or is there a simpler approach I'm missing?
Solution
This will work (as far as I tested) in all 3 cases, if the to-be-inserted values are all new or all already in the table or a mix:
There's probably some other ways to do this, perhaps without using the new
WITH
val (name) AS
( VALUES -- rows to be inserted
('foo'),
('bar'),
('zzz')
),
ins AS
( INSERT INTO
tag (name)
SELECT name FROM val
ON CONFLICT (name) DO NOTHING
RETURNING id, name -- only the inserted ones
)
SELECT COALESCE(ins.id, tag.id) AS id,
val.name
FROM val
LEFT JOIN ins ON ins.name = val.name
LEFT JOIN tag ON tag.name = val.name ;There's probably some other ways to do this, perhaps without using the new
ON CONFLICT syntax.Code Snippets
WITH
val (name) AS
( VALUES -- rows to be inserted
('foo'),
('bar'),
('zzz')
),
ins AS
( INSERT INTO
tag (name)
SELECT name FROM val
ON CONFLICT (name) DO NOTHING
RETURNING id, name -- only the inserted ones
)
SELECT COALESCE(ins.id, tag.id) AS id,
val.name
FROM val
LEFT JOIN ins ON ins.name = val.name
LEFT JOIN tag ON tag.name = val.name ;Context
StackExchange Database Administrators Q#129522, answer score: 16
Revisions (0)
No revisions yet.