Alguns servidores SQL têm um recurso que INSERT
é ignorado se violar uma restrição de chave primária / exclusiva. Por exemplo, o MySQL possui INSERT IGNORE
.
Qual é a melhor maneira de emular INSERT IGNORE
e ON DUPLICATE KEY UPDATE
com o PostgreSQL?
database
postgresql
rules
gpilotino
fonte
fonte
ON DUPLICATE KEY UPDATE
no PgSQL 9.5 ainda é um pouco impossível, porque oON CLAUSE
equivalente ao PgSQL exige que você forneça o nome da restrição, enquanto o MySQL pode capturar qualquer restrição sem a necessidade de defini-la. Isso me impede de "emular" esse recurso sem reescrever consultas.Respostas:
Tente fazer uma atualização. Se não modificar nenhuma linha que significa que não existia, faça uma inserção. Obviamente, você faz isso dentro de uma transação.
É claro que você pode agrupar isso em uma função se não quiser colocar o código extra no lado do cliente. Você também precisa de um loop para a condição de corrida muito rara nesse pensamento.
Há um exemplo disso na documentação: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html , exemplo 40-2, na parte inferior.
Essa é geralmente a maneira mais fácil. Você pode fazer alguma mágica com regras, mas provavelmente será muito mais confuso. Eu recomendaria a abordagem de função de envolvimento em qualquer dia.
Isso funciona para valores de linha única ou poucas linhas. Se você está lidando com grandes quantidades de linhas, por exemplo, de uma subconsulta, é melhor dividi-la em duas consultas, uma para INSERT e outra para UPDATE (como uma junção / subseleção apropriada, é claro - não é necessário escrever sua principal) filtrar duas vezes)
fonte
INSERT ... ON CONFLICT DO NOTHING;
. Consulte também a resposta stackoverflow.com/a/34639631/2091700 .MERGE
é um upsert seguro para simultaneidade, a menos que você faça o primeiro. As pessoas usam dessa maneira, mas está errado.LOCK TABLE
Com o PostgreSQL 9.5, agora é uma funcionalidade nativa (como o MySQL tem há vários anos):
...
fonte
Edit: no caso de você ter perdido a resposta de warren , o PG9.5 agora tem isso nativamente; hora de atualizar!
Com base na resposta de Bill Karwin, para explicar como seria uma abordagem baseada em regras (transferência de outro esquema no mesmo banco de dados e com uma chave primária de várias colunas):
Nota: A regra se aplica a todas as
INSERT
operações até que a regra seja descartada, portanto, não completamente ad hoc.fonte
another_schema.my_table
contém duplicatas de acordo com as restrições demy_table
?INSERT INTO "my_table" SELECT DISTINCT ON (pk_col_1, pk_col_2) * FROM the_tmp_table;
DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY pk_col_1,pk_col_2) AS rn FROM my_table) AS dups WHERE dups.rn > 1);
Para aqueles que possuem o Postgres 9.5 ou superior, a nova sintaxe ON CONFLICT DO NADA deve funcionar:
Para aqueles de nós que possuem uma versão anterior, essa associação correta funcionará:
fonte
Unique violation: 7 ERROR: duplicate key value violates unique constraint
quandotarget_table
tinha outra linha inserido nele enquanto esta consulta estava sendo executado, se as suas chaves, na verdade, duplicar o outro. Acredito que o bloqueiotarget_table
ajudará, mas a concorrência obviamente sofrerá.ON CONFLICT (field_one) DO NOTHING
é a melhor parte da resposta.Para obter a inserção, ignore a lógica, você pode fazer algo como abaixo. Achei que a simples inserção de uma instrução select de valores literais funcionou melhor, então você pode mascarar as chaves duplicadas com uma cláusula NOT EXISTS. Para obter a atualização da lógica duplicada, suspeito que um loop pl / pgsql seria necessário.
fonte
fonte
Parece que o PostgreSQL suporta um objeto de esquema chamado regra .
http://www.postgresql.org/docs/current/static/rules-update.html
Você pode criar uma regra
ON INSERT
para uma determinada tabela, fazendo issoNOTHING
se existir uma linha com o valor da chave primária especificado, ou então fazendo isso emUPDATE
vez deINSERT
se existir uma linha com o valor da chave primária especificado.Eu não tentei isso sozinho, então não posso falar por experiência própria ou dar um exemplo.
fonte
Como @hanmari mencionou em seu comentário. ao inserir em uma tabela do postgres, o conflito on (..) não faz nada é o melhor código a ser usado para não inserir dados duplicados .:
A linha de código ON CONFLICT permitirá que a instrução insert ainda insira linhas de dados. O código de consulta e valores é um exemplo de data inserida de um Excel em uma tabela do postgres db. Tenho restrições adicionadas a uma tabela do postgres que utilizo para garantir que o campo ID seja exclusivo. Em vez de executar uma exclusão em linhas de dados iguais, adiciono uma linha de código sql que renumera a coluna ID iniciando em 1. Exemplo:
Se meus dados tiverem um campo de ID, eu não o uso como o ID primário / ID de série, crio uma coluna de ID e defino-o como serial. Espero que esta informação seja útil para todos. * Não tenho diploma universitário em desenvolvimento / codificação de software. Tudo o que sei em codificação, estudo por conta própria.
fonte
Esta solução evita o uso de regras:
mas tem uma desvantagem de desempenho (consulte PostgreSQL.org ):
fonte
Em massa, você sempre pode excluir a linha antes da inserção. A exclusão de uma linha que não existe não causa um erro, portanto é ignorada com segurança.
fonte
DEFERRABLE INITIALLY DEFERRED
sinalizadores.Para scripts de importação de dados, para substituir "SE NÃO EXISTE", de certa forma, existe uma formulação um pouco estranha que, no entanto, funciona:
fonte