Das INSERT
fügt nur alle Zeilen und nichts ein etwas Besonderes wird passieren, es sei denn Sie haben eine Art Einschränkung doppelte/überlappende Werte nicht zulassen (PRIMARY KEY
, UNIQUE
, CHECK
oder EXCLUDE
Einschränkung) - die Sie in Ihrer Frage nicht erwähnt haben. Aber das ist es, worüber Sie sich wahrscheinlich Sorgen machen.
Angenommen ein UNIQUE
oder PK-Einschränkung für (col1,col2)
, haben Sie es mit einem Lehrbuch UPSERT
zu tun Lage. Viele verwandte Fragen und Antworten finden Sie hier.
Im Allgemeinen, wenn irgendwelche Einschränkung verletzt wird, wird eine Ausnahme ausgelöst, die (sofern sie nicht in einer Subtransaktion gefangen ist, wie es in einer prozeduralen serverseitigen Sprache wie plpgsql möglich ist) nicht nur die Anweisung zurücksetzt, sondern die gesamte Transaktion .
Ohne gleichzeitige Schreibvorgänge
D.h.:Keine anderen Transaktionen werden gleichzeitig versuchen, in dieselbe Tabelle zu schreiben.
-
Schließen Sie Zeilen aus, die sich bereits in der Tabelle befinden, mit
WHERE NOT EXISTS ...
oder jede andere anwendbare Technik: -
Zeilen auswählen, die in keiner anderen Tabelle vorhanden sind
-
Und vergessen Sie nicht, Duplikate innerhalb zu entfernen auch den eingefügten Satz, was nicht wäre durch den Semi-Anti-Join
WHERE NOT EXISTS ...
ausgeschlossen werden
Eine Technik, mit beiden gleichzeitig umzugehen, wä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
ohne das Schlüsselwort ALL
faltet doppelte Zeilen in der Quelle. Wenn Sie wissen, dass es keine Duplikate gibt, oder Sie Duplikate nicht stillschweigend falten möchten, verwenden Sie EXCEPT ALL
(oder eine der anderen Techniken). Siehe:
- Verwenden der EXCEPT-Klausel in PostgreSQL
Im Allgemeinen, wenn die Zieltabelle groß ist , WHERE NOT EXISTS
in Kombination mit DISTINCT
auf der Quelle wird wahrscheinlich schneller sein:
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
);
Wenn es viele Dupes geben kann, lohnt es sich, sie zuerst in der Quelle zu folden. Verwenden Sie andernfalls eine Unterabfrage weniger.
Verwandte:
- Wählen Sie Zeilen aus, die in keiner anderen Tabelle vorhanden sind
Mit gleichzeitigem Schreiben
Verwenden Sie das Postgres-UPSERT
Implementierung INSERT ... ON CONFLICT ...
in Postgres 9.5 oder später:
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!
Weiterführende Literatur:
- Wie verwendet man RETURNING mit ON CONFLICT in PostgreSQL?
- Wie füge ich eine Zeile ein, die einen Fremdschlüssel enthält?
Dokumentation:
- Das Handbuch
- Die Commit-Seite
- Die Postgres-Wiki-Seite
Craigs Referenzantwort für UPSERT
Probleme:
- Wie wird UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL durchgeführt?