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?