sql >> Databasteknik >  >> RDS >> PostgreSQL

Returnera rader från INSERT med ON CONFLICT utan att behöva uppdatera

Det är det återkommande problemet med SELECT or INSERT , relaterad till (men skiljer sig från) en UPSERT. Den nya UPSERT-funktionen i Postgres 9.5 är fortfarande viktig.

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;

På så sätt skriver du faktiskt inte en ny radversion utan behov.

Men , det finns fortfarande ett litet hörnfodral för tävlingsförhållanden . Samtidiga transaktioner kan ha lagt till en motstridig rad, som ännu inte är synlig i samma uttalande. Sedan INSERT och SELECT kom upp tom.

Korrekt lösning för enkelrad UPSERT:

  • Är SELECT eller INSERT i en funktion utsatt för tävlingsförhållanden?

Allmänna lösningar för bulk UPSERT:

  • Hur använder man RETURNING med ON CONFLICT i PostgreSQL?

Utan samtidig skrivbelastning

Om samtidiga skrivningar (från en annan session) inte är möjliga behöver du inte låsa raden och kan förenkla:

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. Hur returnerar jag flera resultatuppsättningar med SqlCommand?

  2. MySQL-ordning efter bästa matchning

  3. Hur man får medarbetarna med sina chefer

  4. Hur man skriver till en CSV-fil med Oracle SQL*Plus