Een oplossing in één SQL-statement. Vereist PostgreSQL 8.4 of later.
Beschouw de volgende demo:
Testopstelling:
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 commando:
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;
-
De eerste CTE v is niet strikt noodzakelijk, maar bereikt dat u uw waarden . moet invoeren slechts één keer.
-
De tweede CTE s selecteert de
idvantblals de "rij" bestaat. -
De derde CTE i voegt de "rij" in
tblals (en alleen als) het niet bestaat, wordtid. geretourneerd . -
De laatste
SELECTgeeft deid. terug . Ik heb een kolom toegevoegdsrcmet vermelding van de "bron" - of de "rij" al bestond enidkomt van een SELECT, of de "rij" was nieuw en dat geldt ook voor deid. -
Deze versie zou zo snel mogelijk moeten zijn aangezien er geen extra SELECT van
tblnodig is en gebruikt in plaats daarvan de CTE's.
Om dit te beveiligen tegen mogelijke race-omstandigheden in een omgeving met meerdere gebruikers:
Ook voor bijgewerkte technieken met behulp van de nieuwe UPSERT in Postgres 9.5 of later:
- Is SELECT of INSERT in een functie die vatbaar is voor race-omstandigheden?