PostgreSQL INSERT ON CONFLICT UPDATE (Upsert) verwendet alle ausgeschlossenen Werte

142

Wenn Sie eine Zeile auf den Kopf stellen (PostgreSQL> = 9.5) und möchten, dass das mögliche INSERT genau dem möglichen UPDATE entspricht, können Sie es folgendermaßen schreiben:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, '[email protected]') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

Gibt es einen kürzeren Weg? Um es nur zu sagen: Verwenden Sie alle EXCLUDE-Werte.

In SQLite habe ich Folgendes gemacht:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, '[email protected]')
Sebastian
quelle
43
Keine echte Antwort, aber Sie können eine kurze Notation verwenden: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, '[email protected]') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).Fast die gleiche, aber einfach zu kopieren / einfügen / verwalten der Spaltenliste
Fohlen
Eine andere Option ist die Verwendung von Jsonb-Spalten, und auf diese Weise müssen Sie sich keine Gedanken über Spalten machen
j wird am

Antworten:

162

Postgres hat kein Äquivalent zu implementiert INSERT OR REPLACE. Aus den ON CONFLICTDokumenten (Schwerpunkt Mine):

Dies kann entweder DO NOTHING oder eine DO UPDATE-Klausel sein, die die genauen Details der UPDATE-Aktion angibt, die im Falle eines Konflikts ausgeführt werden soll.

Dies gilt zwar nicht als Abkürzung für das Ersetzen, ON CONFLICT DO UPDATEgilt jedoch allgemeiner, da Sie damit neue Werte basierend auf bereits vorhandenen Daten festlegen können. Beispielsweise:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;
Kristján
quelle
3
Zur Vorsicht, das "On Update" ist semantisch nicht identisch mit dem "Merge" des SQL-Standards, obwohl es normalerweise an denselben Stellen verwendet werden kann. Ich hatte einen Fall, in dem ich erwartet hatte, dass das "On Conflict Update" aktiviert wird, aber das genaue Problem in der Einfügung hat nicht dazu geführt, dass das Update (das den beschädigten Datensatz repariert hätte) ausgelöst wurde.
Pojo-Typ
2
Können Sie auf "aber das genaue Problem in der Einfügung hat das Update nicht verursacht" erweitern?
MrR
@ pojo-guy - Ich glaube nicht, dass Sie die Frage von MrR gesehen haben - Können Sie weiter gehen "aber das genaue Problem in der Beilage hat das Update nicht verursacht"?
Randall
Wenn Sie versuchen, beim Aktualisieren in postgresql insert ... zu verwenden, unterscheiden sich die Ergebnisse unter bestimmten Umständen von denen einer Zusammenführung. Der Fall, auf den ich stieß, war ziemlich dunkel und spezifisch, aber er war wiederholbar. Es ist ein paar Monate her, also kann ich jetzt nicht mehr geben.
Pojo-Typ
Vielleicht war es kein Konflikt, sondern ein anderer Fehler, z. B. ein Feldtypfehler?
MrR