PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Retorna linhas de INSERT com ON CONFLICT sem precisar atualizar


É o problema recorrente de SELECT or INSERT , relacionado a (mas diferente de) um UPSERT. A nova funcionalidade UPSERT no Postgres 9.5 ainda é fundamental.
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;

Dessa forma, você não escreve uma nova versão de linha sem necessidade.



No entanto , ainda há um pequeno caso de curva para uma condição de corrida . As transações simultâneas podem ter adicionado uma linha conflitante, que ainda não está visível na mesma instrução. Então INSERT e SELECT venha vazio.

Solução adequada para UPSERT de linha única:
  • O SELECT ou INSERT está em uma função propensa a condições de corrida?

Soluções gerais para UPSERT a granel:
  • Como usar RETURNING com ON CONFLICT no PostgreSQL?

Sem carga de gravação simultânea


Se gravações simultâneas (de uma sessão diferente) não forem possíveis, você não precisará bloquear a linha e poderá simplificar:
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;