INSERT
pouze vloží všechny řádky a nic se stane zvláštní, pokud máte nějaké omezení zakázání duplicitních / překrývajících se hodnot (PRIMARY KEY
, UNIQUE
, CHECK
nebo EXCLUDE
omezení) – které jste ve své otázce nezmínil. Ale to je to, čeho se pravděpodobně obáváte.
Za předpokladu UNIQUE
nebo PK omezení na (col1,col2)
, máte co do činění s učebnicí UPSERT
situace. Mnoho souvisejících otázek a odpovědí naleznete zde.
Obecně platí, že nějaké omezení je porušeno, je vyvolána výjimka, která (pokud není uvězněna v dílčí transakci, jak je to možné v procedurálním jazyce na straně serveru, jako je plpgsql) vrátí zpět nejen příkaz, ale celou transakci .
Bez souběžných zápisů
T.j.:Žádné jiné transakce se nepokusí zapisovat do stejné tabulky ve stejnou dobu.
-
Vyloučit řádky, které již v tabulce jsou, pomocí
WHERE NOT EXISTS ...
nebo jakoukoli jinou použitelnou technikou: -
Vyberte řádky, které nejsou přítomny v jiné tabulce
-
A nezapomeňte odstranit duplikáty v rámci vložená sada také, což by nebylo být vyloučen pomocí semi-anti-join
WHERE NOT EXISTS ...
Jedna technika, jak se vypořádat s oběma najednou, by byla 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
bez klíčového slova ALL
složí duplicitní řádky ve zdroji. Pokud víte, že neexistují žádní podvodníci nebo nechcete duplikáty potichu skládat, použijte EXCEPT ALL
(nebo některou z dalších technik). Viz:
- Použití klauzule EXCEPT v PostgreSQL
Obecně platí, že pokud je cílová tabulka velká , WHERE NOT EXISTS
v kombinaci s DISTINCT
na zdroji bude pravděpodobně rychlejší:
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
);
Pokud může být dupů mnoho, vyplatí se je nejprve složit do zdroje. Jinak použijte o jeden dílčí dotaz méně.
Související:
- Vyberte řádky, které se nenacházejí v jiné tabulce
Se souběžným zápisem
Použijte Postgres UPSERT
implementace INSERT ... ON CONFLICT ...
v Postgres 9.5 nebo později:
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!
Další čtení:
- Jak používat RETURNING s ON CONFLICT v PostgreSQL?
- Jak vložím řádek, který obsahuje cizí klíč?
Dokumentace:
- Příručku
- Stránka potvrzení
- Stránka Postgres Wiki
Craigova referenční odpověď pro UPSERT
problémy:
- Jak UPSERT (SLOUČIT, VLOŽIT ... PŘI DUPLIKÁTNÍ AKTUALIZACI) v PostgreSQL?