sql >> Database >  >> RDS >> PostgreSQL

Wat gebeurt er met duplicaten bij het invoegen van meerdere rijen?

De INSERT voegt gewoon alle rijen in en niets speciaal zal gebeuren, tenzij je hebt een soort van beperking dubbele / overlappende waarden niet toestaan ​​(PRIMARY KEY , UNIQUE , CHECK of EXCLUDE beperking) - die u niet vermeldde in uw vraag. Maar daar maak je je waarschijnlijk zorgen over.

Uitgaande van een UNIQUE of PK-beperking op (col1,col2) , je hebt te maken met een leerboek UPSERT situatie. Veel gerelateerde vragen en antwoorden zijn hier te vinden.

Over het algemeen, indien enig beperking wordt geschonden, wordt een uitzondering gemaakt die (tenzij gevangen in subtransactie zoals het mogelijk is in een procedurele server-side taal zoals plpgsql) niet alleen de instructie terugdraait, maar de hele transactie .

Zonder gelijktijdige schrijfbewerkingen

D.w.z.:geen enkele andere transactie zal tegelijkertijd proberen naar dezelfde tafel te schrijven.

  • Sluit rijen uit die al in de tabel staan ​​met WHERE NOT EXISTS ... of een andere toepasselijke techniek:

  • Selecteer rijen die niet aanwezig zijn in een andere tabel

  • En vergeet niet om duplicaten te verwijderen binnen de ingevoegde set ook, wat niet . zou zijn worden uitgesloten door de semi-anti-join WHERE NOT EXISTS ...

Een techniek om met beide tegelijk om te gaan is 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 zonder het sleutelwoord ALL vouwt dubbele rijen in de bron. Als je weet dat er geen dupes zijn, of als je duplicaten niet stil wilt vouwen, gebruik dan EXCEPT ALL (of een van de andere technieken). Zie:

  • De clausule EXCEPT gebruiken in PostgreSQL

Over het algemeen, als de doeltabel groot is , WHERE NOT EXISTS in combinatie met DISTINCT op de bron zal waarschijnlijk sneller zijn:

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
   );

Als er veel dupes kunnen zijn, loont het om ze eerst in de source te folden. Gebruik anders één subquery minder.

Gerelateerd:

  • Selecteer rijen die niet aanwezig zijn in een andere tabel

Met gelijktijdige schrijfbewerkingen

Gebruik de Postgres UPSERT implementatie INSERT ... ON CONFLICT ... in Postgres 9.5 of later:

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!

Verder lezen:

  • Hoe RETURNING gebruiken met ON CONFLICT in PostgreSQL?
  • Hoe voeg ik een rij in die een externe sleutel bevat?

Documentatie:

  • De handleiding
  • De vastleggingspagina
  • De Postgres Wiki-pagina

Craig's referentieantwoord voor UPSERT problemen:

  • Hoe UPERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?


  1. Waarschuwing:mysql_query():3 is geen geldige MySQL-Link-bron

  2. door komma's gescheiden lijst als een enkele tekenreeks, T-SQL

  3. Hoe te ontsnappen aan enkele aanhalingstekens in MySQL

  4. Hoe de sortering van een tabel in MySQL te tonen