Warnung: Dies ist nicht sicher, wenn es gleichzeitig aus mehreren Sitzungen ausgeführt wird (siehe unten stehende Warnungen).
Ein weiterer intelligenter Weg, um ein "UPSERT" in PostgreSQL durchzuführen, besteht darin, zwei aufeinanderfolgende UPDATE/INSERT-Anweisungen auszuführen, die jeweils darauf ausgelegt sind, erfolgreich zu sein oder keine Auswirkungen zu haben.
UPDATE tabelle SET feld='C', feld2='Z' WHERE id=3;
INSERT INTO tabelle (id, feld, feld2)
SELECT 3, 'C', 'Z'
WHERE NOT EXISTS (SELECT 1 FROM tabelle WHERE id=3);
Das UPDATE wird erfolgreich sein, wenn bereits eine Zeile mit "id=3" existiert, andernfalls hat es keine Auswirkung.
Das INSERT wird nur erfolgreich sein, wenn die Zeile mit "id=3" noch nicht existiert.
Sie können diese beiden in einen einzelnen String kombinieren und sie beide mit einer einzelnen SQL-Anweisung von Ihrer Anwendung ausführen. Es wird dringend empfohlen, sie zusammen in einer einzelnen Transaktion auszuführen.
Dies funktioniert sehr gut, wenn es isoliert oder auf einer gesperrten Tabelle ausgeführt wird, ist jedoch anfällig für Wettlaufbedingungen, die bedeuten, dass es trotzdem mit einem Fehler für doppelten Schlüssel fehlschlagen könnte, wenn eine Zeile gleichzeitig eingefügt wird, oder mit keiner eingefügte Zeile enden könnte, wenn eine Zeile gleichzeitig gelöscht wird. Eine SERIALIZABLE
Transaktion in PostgreSQL 9.1 oder höher wird dies zuverlässig behandeln, allerdings mit einer sehr hohen Serienfehlerrate, was bedeutet, dass Sie es möglicherweise viele Male wiederholen müssen. Siehe warum ist upsert so kompliziert, das diesen Fall genauer diskutiert.
Dieser Ansatz ist auch anfällig für verlorene Updates in der read committed
Isolation, es sei denn, die Anwendung überprüft die betroffenen Zeilenzahlen und stellt fest, dass entweder das insert
oder das update
eine Zeile betroffen hat.
46 Stimmen
Jeder, der diese Frage findet, sollte den Artikel von Depesz "Warum ist upsert so kompliziert?" lesen. Es erklärt das Problem und mögliche Lösungen sehr gut.
9 Stimmen
UPSERT wird in Postgres 9.5 hinzugefügt: wiki.postgresql.org/wiki/…
6 Stimmen
@tommed - es wurde erledigt: stackoverflow.com/a/34639631/4418