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
idaustblwenn die "Zeile" existiert. -
Der dritte CTE i fügt ein die "Zeile" in
tblwenn (und nur wenn) es nicht existiert, wirdidzurückgegeben . -
Das letzte
SELECTgibt dieidzurück . Ich habe eine Spaltesrchinzugefügt Angabe der "Quelle" - ob die "Zeile" bereits existierte undidstammt 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
tblbenö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?