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
id
vantbl
als de "rij" bestaat. -
De derde CTE i voegt de "rij" in
tbl
als (en alleen als) het niet bestaat, wordtid
. geretourneerd . -
De laatste
SELECT
geeft deid
. terug . Ik heb een kolom toegevoegdsrc
met vermelding van de "bron" - of de "rij" al bestond enid
komt 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
tbl
nodig 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?