sql >> Databáze >  >> RDS >> PostgreSQL

Co se stane s duplikáty při vkládání více řádků?

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?


  1. Upgrade Grid Control po ručním upgradu DB

  2. Začínáme s GearHost pro vývoj databáze SQL Server

  3. Jak zřetězit text z více řádků do jednoho textového řetězce na serveru SQL Server

  4. Jak automaticky zavřít nečinná připojení v PostgreSQL?