Het is het terugkerende probleem van SELECT or INSERT
, gerelateerd aan (maar verschillend van) een UPSERT. De nieuwe UPSERT-functionaliteit in Postgres 9.5 is nog steeds instrumenteel.
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO UPDATE
SET name = NULL
WHERE FALSE -- never executed, but locks the row
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;
Op deze manier schrijf je niet echt een nieuwe rijversie zonder dat het nodig is.
Echter , er is nog een klein hoekje voor een raceconditie . Bij gelijktijdige transacties is mogelijk een conflicterende rij toegevoegd, die nog niet zichtbaar is in hetzelfde overzicht. Dan INSERT
en SELECT
kom leeg.
Juiste oplossing voor UPSERT met één rij:
- Is SELECT of INSERT in een functie die vatbaar is voor race-omstandigheden?
Algemene oplossingen voor bulk UPSERT:
- Hoe RETURNING gebruiken met ON CONFLICT in PostgreSQL?
Zonder gelijktijdige schrijfbelasting
Als gelijktijdig schrijven (van een andere sessie) niet mogelijk is, hoeft u de rij niet te vergrendelen en kunt u het volgende vereenvoudigen:
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO NOTHING -- no lock needed
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;