PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Restituisce le righe da INSERT con ON CONFLICT senza dover aggiornare

È il problema ricorrente di SELECT or INSERT , relativo a (ma diverso da) un UPSERT. La nuova funzionalità UPSERT in Postgres 9.5 è ancora fondamentale.

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;

In questo modo non scrivi effettivamente una nuova versione di riga senza bisogno.

Tuttavia , c'è ancora un piccolo caso d'angolo per una condizione di gara . Le transazioni simultanee potrebbero aver aggiunto una riga in conflitto, che non è ancora visibile nella stessa dichiarazione. Quindi INSERT e SELECT torna vuoto.

Soluzione adeguata per UPSERT a riga singola:

  • SELEZIONA o INSERT in una funzione soggetta a condizioni di gara?

Soluzioni generali per UPSERT in blocco:

  • Come utilizzare RETURNING con ON CONFLICT in PostgreSQL?

Senza carico di scrittura simultaneo

Se le scritture simultanee (da una sessione diversa) non sono possibili non è necessario bloccare la riga e puoi semplificare:

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;