Einige SQL Server verfügen über eine Funktion, die INSERT
übersprungen wird, wenn sie eine Primär- / eindeutige Schlüsselbeschränkung verletzt. Zum Beispiel hat MySQL INSERT IGNORE
.
Was ist der beste Weg, um INSERT IGNORE
und ON DUPLICATE KEY UPDATE
mit PostgreSQL zu emulieren ?
database
postgresql
rules
gpilotino
quelle
quelle
ON DUPLICATE KEY UPDATE
PgSQL 9.5 ist dies immer noch nicht möglich, daON CLAUSE
Sie für das PgSQL- Äquivalent den Namen der Einschränkung angeben müssen, während MySQL jede Einschränkung erfassen kann, ohne sie definieren zu müssen. Dies verhindert, dass ich diese Funktion "emuliere", ohne Abfragen neu zu schreiben.Antworten:
Versuchen Sie ein UPDATE durchzuführen. Wenn keine Zeile geändert wird, die bedeutet, dass sie nicht vorhanden ist, fügen Sie sie ein. Offensichtlich tun Sie dies innerhalb einer Transaktion.
Sie können dies natürlich in eine Funktion einbinden, wenn Sie den zusätzlichen Code nicht auf der Clientseite platzieren möchten. Sie brauchen auch eine Schleife für die sehr seltene Rennbedingung in diesem Denken.
Ein Beispiel hierfür finden Sie in der Dokumentation: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html , Beispiel 40-2 ganz unten.
Das ist normalerweise der einfachste Weg. Sie können mit Regeln etwas zaubern, aber es wird wahrscheinlich viel chaotischer. Ich würde den Wrap-in-Function-Ansatz jeden Tag empfehlen.
Dies funktioniert für einzelne oder wenige Zeilenwerte. Wenn Sie beispielsweise mit einer großen Anzahl von Zeilen aus einer Unterabfrage arbeiten, teilen Sie diese am besten in zwei Abfragen auf, eine für INSERT und eine für UPDATE (natürlich als geeignete Verknüpfung / Unterauswahl - Sie müssen Ihre Hauptabfrage nicht schreiben zweimal filtern)
quelle
INSERT ... ON CONFLICT DO NOTHING;
. Siehe auch Antwort stackoverflow.com/a/34639631/2091700 .MERGE
ist kein sicherer Upsert für Parallelität, es sei denn, Sie nehmen einenLOCK TABLE
ersten. Die Leute benutzen es so, aber es ist falsch.Mit PostgreSQL 9.5 ist dies nun eine native Funktionalität (wie sie MySQL seit mehreren Jahren hat):
...
quelle
Bearbeiten: Falls Sie die Antwort von Warren verpasst haben , hat PG9.5 diese nun nativ; Zeit für ein Upgrade!
Aufbauend auf der Antwort von Bill Karwin, um darzulegen, wie ein regelbasierter Ansatz aussehen würde (Übertragung von einem anderen Schema in derselben Datenbank und mit einem mehrspaltigen Primärschlüssel):
Hinweis: Die Regel gilt für alle
INSERT
Vorgänge, bis die Regel gelöscht wird, also nicht ganz ad hoc.quelle
another_schema.my_table
Duplikate gemäß den Einschränkungen vonmy_table
?INSERT INTO "my_table" SELECT DISTINCT ON (pk_col_1, pk_col_2) * FROM the_tmp_table;
DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY pk_col_1,pk_col_2) AS rn FROM my_table) AS dups WHERE dups.rn > 1);
Für diejenigen unter Ihnen, die Postgres 9.5 oder höher haben, sollte die neue Syntax ON CONFLICT DO NOTHING funktionieren:
Für diejenigen von uns, die eine frühere Version haben, funktioniert dieser richtige Join stattdessen:
quelle
Unique violation: 7 ERROR: duplicate key value violates unique constraint
wenntarget_table
eine andere Zeile eingefügt wurde, während diese Abfrage ausgeführt wurde, wenn sich ihre Schlüssel tatsächlich gegenseitig duplizieren. Ich glaube, dass das Sperrentarget_table
helfen wird, aber die Parallelität wird offensichtlich leiden.ON CONFLICT (field_one) DO NOTHING
ist der beste Teil der Antwort.Um die Logik zum Ignorieren des Einfügens zu erhalten, können Sie wie folgt vorgehen . Ich fand, dass das Einfügen aus einer select-Anweisung von Literalwerten am besten funktioniert. Dann können Sie die doppelten Schlüssel mit einer NOT EXISTS-Klausel ausblenden. Um das Update auf doppelte Logik zu bekommen, vermute ich, dass eine pl / pgsql-Schleife notwendig wäre.
quelle
quelle
Es sieht so aus, als ob PostgreSQL ein Schemaobjekt unterstützt, das als Regel bezeichnet wird .
http://www.postgresql.org/docs/current/static/rules-update.html
Sie könnten eine Regel erstellen ,
ON INSERT
für eine bestimmte Tabelle, es tut zu machen ,NOTHING
wenn eine Zeile mit dem angegebenen Primärschlüsselwert vorhanden ist , sonst macht es noch einUPDATE
statt der ,INSERT
wenn eine Zeile mit dem Primärschlüsselwert gegeben existiert.Ich habe es selbst nicht versucht, daher kann ich nicht aus Erfahrung sprechen oder ein Beispiel anbieten.
quelle
Wie @hanmari in seinem Kommentar erwähnt. Beim Einfügen in eine Postgres-Tabelle ist der On-Konflikt (..) nichts zu tun der beste Code, um keine doppelten Daten einzufügen:
Mit der Codezeile ON CONFLICT kann die insert-Anweisung weiterhin Datenzeilen einfügen. Der Abfrage- und Wertecode ist ein Beispiel für das Einfügen eines Datums aus einem Excel in eine Postgres-DB-Tabelle. Ich habe einer Postgres-Tabelle, die ich verwende, Einschränkungen hinzugefügt, um sicherzustellen, dass das ID-Feld eindeutig ist. Anstatt einen Löschvorgang für dieselben Datenzeilen auszuführen, füge ich eine Zeile SQL-Code hinzu, die die ID-Spalte ab 1 neu nummeriert. Beispiel:
Wenn meine Daten ein ID-Feld haben, verwende ich dieses nicht als primäre ID / serielle ID. Ich erstelle eine ID-Spalte und setze sie auf seriell. Ich hoffe, diese Informationen sind für alle hilfreich. * Ich habe keinen Hochschulabschluss in Softwareentwicklung / -codierung. Alles, was ich im Codieren weiß, lerne ich selbst.
quelle
Diese Lösung vermeidet die Verwendung von Regeln:
Es hat jedoch einen Leistungsnachteil (siehe PostgreSQL.org ):
quelle
In großen Mengen können Sie die Zeile immer vor dem Einfügen löschen. Das Löschen einer nicht vorhandenen Zeile verursacht keinen Fehler und wird daher sicher übersprungen.
quelle
DEFERRABLE INITIALLY DEFERRED
Flags erstellen .Für Datenimport-Skripte gibt es eine etwas umständliche Formulierung, die dennoch funktioniert, um "WENN NICHT EXISTIERT" zu ersetzen:
quelle