Ich schreibe eine Funktion in node.js, um eine PostgreSQL-Tabelle abzufragen.
Wenn die Zeile vorhanden ist, möchte ich die ID-Spalte aus der Zeile zurückgeben.
Wenn es nicht existiert, möchte ich es einfügen und die ID ( insert into ... returning id
) zurückgeben.
Ich habe versucht, Variationen von case
und if else
-Anweisungen zu versuchen und es scheint nicht zu funktionieren.
Eine Lösung in einer einzelnen SQL-Anweisung. Benötigt PostgreSQL 8.4 oder später.
Betrachten Sie die folgende Demo:
Testeinrichtung:
%Vor%INSERT / SELECT-Befehl:
%Vor%Der erste CTE v ist nicht unbedingt erforderlich, aber Sie müssen Ihre Werte nur einmal eingeben.
Der zweite CTE s wählt das id
von tbl
aus, wenn die "Zeile" existiert.
Der dritte CTE i fügt die "row" in tbl
ein, wenn (und nur wenn) es nicht existiert und id
zurückgibt.
Der letzte SELECT
gibt den id
zurück. Ich fügte eine Spalte src
hinzu, die die "Quelle" angibt - ob die "Zeile" bereits existierte und id
von einem SELECT kam, oder die "Zeile" war neu und das ist auch id
.
Diese Version sollte so schnell wie möglich sein, da sie kein zusätzliches SELECT von tbl
benötigt und stattdessen die CTEs verwendet.
Um dies vor möglichen Rennbedingungen in einer Mehrbenutzerumgebung zu schützen:
Auch für aktualisierte Techniken, die den neuen UPSERT in Postgres 9.5 oder später verwenden:
So etwas, wenn Sie auf PostgreSQL 9.1 sind
%Vor%Es ist ein bisschen länglich und Sie müssen die ID wiederholen, um mehrere Male zu testen, aber ich kann mir keine andere Lösung vorstellen, die eine einzelne SQL-Anweisung beinhaltet.
Wenn eine Zeile mit id=42
vorhanden ist, fügt der beschreibbare CTE nichts ein und die vorhandene Zeile wird daher vom zweiten Union-Teil zurückgegeben.
Beim Testen dachte ich eigentlich, dass die neue Zeile zweimal zurückgegeben würde (also ein union
nicht ein union all
), aber es stellt sich heraus, dass das Ergebnis der zweiten SELECT-Anweisung tatsächlich ausgewertet wird, bevor die gesamte Anweisung ausgeführt wird Die neu eingefügte Zeile wird nicht angezeigt. Wenn also eine neue Zeile eingefügt wird, wird sie aus dem "zurückkehrenden" Teil übernommen.
Tags und Links sql node.js postgresql sql-insert