INSERT
vil bare indsætte alle rækker og ingenting særlige vil ske, medmindre du har en form for begrænsning ikke tillade duplikerede/overlappende værdier (PRIMARY KEY
, UNIQUE
, CHECK
eller EXCLUDE
constraint) - som du ikke nævnte i dit spørgsmål. Men det er du sikkert bekymret over.
Forudsat en UNIQUE
eller PK-begrænsning på (col1,col2)
, du har at gøre med en lærebog UPSERT
situation. Mange relaterede spørgsmål og svar at finde her.
Generelt, hvis nogen begrænsning er overtrådt, er der rejst en undtagelse, som (medmindre fanget i subtransaktion som det er muligt i et proceduremæssigt server-side sprog som plpgsql) vil rulle tilbage ikke kun erklæringen, men hele transaktionen .
Uden samtidige skrivninger
Dvs.:Ingen andre transaktioner vil forsøge at skrive til den samme tabel på samme tid.
-
Ekskluder rækker, der allerede er i tabellen med
WHERE NOT EXISTS ...
eller enhver anden anvendelig teknik: -
Vælg rækker, der ikke er til stede i anden tabel
-
Og glem ikke at fjerne dubletter indenfor det indsatte sæt også, hvilket ikke ville blive udelukket af semi-anti-join
WHERE NOT EXISTS ...
En teknik til at håndtere begge dele på én gang ville være 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
uden nøgleordet ALL
folder duplikerede rækker i kilden. Hvis du ved, at der ikke er nogen duplikater, eller du ikke ønsker at folde dubletter stille, skal du bruge EXCEPT ALL
(eller en af de andre teknikker). Se:
- Ved brug af EXCEPT-sætning i PostgreSQL
Generelt, hvis måltabellen er stor , WHERE NOT EXISTS
i kombination med DISTINCT
på kilden vil sandsynligvis være hurtigere:
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
);
Hvis der kan være mange duper, kan det betale sig at folde dem i kilden først. Ellers brug en underforespørgsel mindre.
Relateret:
- Vælg rækker, der ikke findes i en anden tabel
Med samtidig skrivning
Brug Postgres UPSERT
implementering INSERT ... ON CONFLICT ...
i Postgres 9.5 eller senere:
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!
Yderligere læsning:
- Hvordan bruger man RETURNING med ON CONFLICT i PostgreSQL?
- Hvordan indsætter jeg en række, der indeholder en fremmednøgle?
Dokumentation:
- Manualen
- Forpligtelsessiden
- Postgres Wiki-siden
Craigs referencesvar for UPSERT
problemer:
- Hvordan UPSERT (FLETT, INDSÆT ... VED DUPLIKAT OPDATERING) i PostgreSQL?