O
INSERT apenas inserirá todas as linhas e nada especial acontecerá, a menos que você tem algum tipo de restrição não permitindo valores duplicados/sobrepostos (PRIMARY KEY , UNIQUE , CHECK ou EXCLUDE restrição) - que você não mencionou em sua pergunta. Mas é com isso que você provavelmente está preocupado. Assumindo um
UNIQUE ou restrição PK em (col1,col2) , você está lidando com um livro UPSERT situação. Muitas perguntas e respostas relacionadas para encontrar aqui. Geralmente, se qualquer restrição é violada, uma exceção é gerada que (a menos que seja presa em subtransação como é possível em uma linguagem procedural do lado do servidor como plpgsql) reverterá não apenas a instrução, mas a transação inteira .
Sem gravações simultâneas
Ou seja:Nenhuma outra transação tentará gravar na mesma tabela ao mesmo tempo.
-
Excluir linhas que já estão na tabela comWHERE NOT EXISTS ...ou qualquer outra técnica aplicável:
-
Selecione linhas que não estão presentes em outra tabela
-
E não se esqueça de remover duplicatas dentro o conjunto inserido também, o que não ser excluído pelo semi-anti-joinWHERE NOT EXISTS ...
Uma técnica para lidar com ambos ao mesmo tempo seria
EXCEPT :INSERT INTO tbl (col1, col2)
VALUES
(text 'v1', text 'v2') -- explicit type cast may be needed in 1st row
, ('v3', 'v4')
, ('v3', 'v4') -- beware of dupes in source
EXCEPT SELECT col1, col2 FROM tbl;
EXCEPT sem a palavra chave ALL dobra linhas duplicadas na fonte. Se você sabe que não há dupes ou não deseja dobrar duplicatas silenciosamente, use EXCEPT ALL (ou uma das outras técnicas). Ver:- Usando a cláusula EXCEPT no PostgreSQL
Geralmente, se a tabela de destino for grande ,
WHERE NOT EXISTS em combinação com DISTINCT na fonte provavelmente será mais rápido:INSERT INTO tbl (col1, col2)
SELECT *
FROM (
SELECT DISTINCT *
FROM (
VALUES
(text 'v1', text'v2')
, ('v3', 'v4')
, ('v3', 'v4') -- dupes in source
) t(c1, c2)
) t
WHERE NOT EXISTS (
SELECT FROM tbl
WHERE col1 = t.c1 AND col2 = t.c2
);
Se pode haver muitos trapaceiros, vale a pena dobrá-los na fonte primeiro. Caso contrário, use uma subconsulta a menos.
Relacionado:
- Selecione as linhas que não estão presentes em outra tabela
Com gravações simultâneas
Use o
UPSERT do Postgres implementação INSERT ... ON CONFLICT ... no Postgres 9.5 ou mais tarde:INSERT INTO tbl (col1,col2)
SELECT DISTINCT * -- still can't insert the same row more than once
FROM (
VALUES
(text 'v1', text 'v2')
, ('v3','v4')
, ('v3','v4') -- you still need to fold dupes in source!
) t(c1, c2)
ON CONFLICT DO NOTHING; -- ignores rows with *any* conflict!
Leitura adicional:
- Como usar RETURNING com ON CONFLICT no PostgreSQL?
- Como insiro uma linha que contém uma chave estrangeira?
Documentação:
- Manual
- A página de confirmação
- A página do Postgres Wiki
Resposta de referência de Craig para
UPSERT problemas:- Como UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) no PostgreSQL?