sql >> Database >  >> RDS >> PostgreSQL

Retourneer rijen van INSERT met ON CONFLICT zonder te updaten

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;



  1. Oracle - Gematerialiseerde weergave nog steeds toegankelijk tijdens volledige vernieuwing. Hoe werkt dit?

  2. T-SQL - Gegevens in bovenliggende en onderliggende tabellen invoegen

  3. Oracle 12c Installation heeft geen toegang tot de tijdelijke locatie

  4. Een inconsistente PostgreSQL-slave opnieuw opbouwen