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?