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, '[email protected]') 
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, '[email protected]')
Sebastian
fonte
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, '[email protected]') 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;
Kristján
fonte
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