Eine Lösung in einer einzigen SQL-Anweisung. Erfordert PostgreSQL 8.4 oder später.
Betrachten Sie die folgende Demo:
Testaufbau:
CREATE TEMP TABLE tbl (
id serial PRIMARY KEY
,txt text UNIQUE -- obviously there is unique column (or set of columns)
);
INSERT INTO tbl(txt) VALUES ('one'), ('two');
INSERT / SELECT-Befehl:
WITH v AS (SELECT 'three'::text AS txt)
,s AS (SELECT id FROM tbl JOIN v USING (txt))
,i AS (
INSERT INTO tbl (txt)
SELECT txt
FROM v
WHERE NOT EXISTS (SELECT * FROM s)
RETURNING id
)
SELECT id, 'i'::text AS src FROM i
UNION ALL
SELECT id, 's' FROM s;
-
Der erste CTE v ist nicht zwingend erforderlich, bewirkt aber, dass Sie Ihre Werte eingeben müssen nur einmal.
-
Der zweite CTE s wählt aus die
id
austbl
wenn die "Zeile" existiert. -
Der dritte CTE i fügt ein die "Zeile" in
tbl
wenn (und nur wenn) es nicht existiert, wirdid
zurückgegeben . -
Das letzte
SELECT
gibt dieid
zurück . Ich habe eine Spaltesrc
hinzugefügt Angabe der "Quelle" - ob die "Zeile" bereits existierte undid
stammt aus einem SELECT, oder die "Zeile" war neu und ebenso dieid
. -
Diese Version sollte so schnell wie möglich sein, da sie kein zusätzliches SELECT von
tbl
benötigt und verwendet stattdessen die CTEs.
Um dies gegen mögliche Racebedingungen in einer Umgebung mit mehreren Benutzern abzusichern:
Auch für aktualisierte Techniken mit dem neuen UPSERT in Postgres 9.5 oder später:
- Ist SELECT oder INSERT in einer Funktion anfällig für Race-Conditions?