Erhalte die Id von einem bedingten INSERT

8

Für eine Tabelle wie diese:

%Vor%

Was wäre die korrekte Ein-Abfrage-Einfügung für die folgende Operation:

Geben Sie für einen Benutzer name einen neuen Datensatz ein und geben Sie den neuen id zurück. Aber wenn der name bereits existiert, gib einfach id zurück.

Ich kenne die neue Syntax in PostgreSQL 9.5 für ON CONFLICT(column) DO UPDATE/NOTHING , aber ich kann nicht herausfinden, wie, wenn überhaupt, kann es helfen, da ich id zurückgeben muss.

Es scheint, dass RETURNING id und ON CONFLICT nicht zusammen gehören.

    
vitaly-t 18.03.2016, 11:53
quelle

2 Antworten

7

Die UPSERT-Implementierung ist äußerst komplex, um vor gleichzeitigem Schreibzugriff zu schützen. Werfen Sie einen Blick auf dieses Postgres-Wiki , das während der anfänglichen Entwicklung als Protokoll diente. Die Postgres-Hacker entschieden, keine "ausgeschlossenen" Zeilen in die RETURNING -Klausel für die erste Veröffentlichung in Postgres 9.5 aufzunehmen. Sie könnten etwas für die nächste Veröffentlichung einbauen.

Dies ist die entscheidende Aussage im Handbuch, um Ihre Situation zu erklären:

  

Die Syntax der RETURNING -Liste ist identisch mit der der Ausgabe   Liste von SELECT . Nur Zeilen, die erfolgreich eingefügt oder aktualisiert wurden   wird zurückgegeben. Beispiel: Eine Zeile wurde gesperrt, aber nicht aktualisiert   weil eine ON CONFLICT DO UPDATE ... WHERE -Klauselbedingung nicht war   zufrieden, die Zeile wird nicht zurückgegeben.

Fett Hervorhebung meins.

Für eine einzelne Zeile einfügen:

%Vor%

Oder wrap in eine Funktion, um nur den neuen Namen einmal anzugeben. Wie hier demonstriert (beachte auch die Erklärung für LIMIT 1 ):

Das mögliche Rennen: Eine gleichzeitige Transaktion könnte die bestehende Zeile zwischen dem INSERT Versuch und dem SELECT ändern / entfernen. Sehr unwahrscheinlich, aber möglich.

Wenn Sie (möglicherweise) keinen gleichzeitigen Schreibzugriff haben (oder einfach nicht interessiert), vereinfachen Sie:

%Vor%

Um einen Satz von Zeilen einzufügen :

Erwin Brandstetter 18.03.2016, 17:31
quelle
2

Für eine einzelne Zeile einfügen und keine Aktualisierung:

%Vor%

Das Handbuch zu den primären und with Unterabfragen Teile:

  

Die primäre Abfrage und die WITH-Abfragen werden alle gleichzeitig ( fiktiv ) ausgeführt

Obwohl mir das "selbe Schnappschuss" klingt, bin ich mir nicht sicher, da ich nicht weiß, was fiktiv in diesem Kontext bedeutet.

Aber gibt es auch :

  

Die Unteranweisungen in WITH werden gleichzeitig miteinander und mit der Hauptabfrage ausgeführt. Wenn Sie also datenverändernde Anweisungen in WITH verwenden, ist die Reihenfolge, in der die angegebenen Aktualisierungen tatsächlich stattfinden, nicht vorhersagbar. Alle Anweisungen werden mit demselben Snapshot ausgeführt

Wenn ich richtig verstehe, dass selbe Snapshot Bit eine Race-Bedingung verhindert. Aber ich bin mir auch nicht sicher, ob sich alle Anweisungen nur auf die Anweisungen in den with Unterabfragen ohne die Hauptabfrage bezieht. Um Zweifel zu vermeiden, verschieben Sie die Auswahl in der vorherigen Abfrage in eine with Unterabfrage:

%Vor%     
Clodoaldo Neto 18.03.2016 12:28
quelle

Tags und Links