INSERÇÃO do PostgreSQL na atualização de conflito (upsert) usa todos os valores excluídos


142

Quando você está upserting uma linha (PostgreSQL> = 9.5) e deseja que o INSERT possível seja exatamente o mesmo que o UPDATE possível, você pode escrevê-lo assim:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

Existe um caminho mais curto? Para dizer apenas: use todos os valores EXCLUDE.

No SQLite, eu costumava fazer:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, 'john@mail.com')

43
Não é uma resposta real, mas você pode usar um pouco logo notação: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).Quase a mesma, mas fácil de copiar / colar / gerenciar a lista de colunas
— potro

Outra opção é usar as colunas jsonb e dessa forma você não precisa se preocupar com colunas
— j será

Respostas:


162

O Postgres não implementou um equivalente a INSERT OR REPLACE. Dos ON CONFLICTdocumentos (ênfase minha):

Pode ser DO NADA ou uma cláusula DO UPDATE especificando os detalhes exatos da ação UPDATE a ser executada em caso de conflito.

Embora não seja um atalho para substituição, ON CONFLICT DO UPDATEaplica-se de maneira mais geral, pois permite definir novos valores com base em dados preexistentes. Por exemplo:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;

3
Como uma palavra de cautela, o "na atualização" não é semanticamente idêntico ao "mesclagem" do padrão SQL, embora possa geralmente ser usado nos mesmos locais. Tive um caso em que esperava que a "atualização em conflito" iniciasse, mas o problema exato na inserção não causou o lançamento da atualização (que teria reparado o registro danificado).
— pojo-guy

2
Você pode expandir "mas o problema exato na inserção não causou a atualização"?
— MrR 18/12/19

@ pojo-guy - Eu não acho que você viu a pergunta do MrR - Você pode expandir "mas o problema exato na inserção não causou a atualização"?
— Randall

Quando você tenta usar a inserção ... na atualização no postgresql, os resultados são diferentes em algumas circunstâncias específicas que uma mesclagem. O caso que encontrei era bastante obscuro e específico, mas era repetível. Faz alguns meses, então não posso dar mais certo agora.
— precisa

Talvez não tenha sido um conflito, mas outro erro, por exemplo, erro de tipo de campo?
— MrR 31/01/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.