Řešení v jediném SQL příkazu. Vyžaduje PostgreSQL 8.4 nebo později.
Zvažte následující ukázku:
Testovací nastavení:
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');
Příkaz INSERT / SELECT:
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;
-
První CTE v není nezbytně nutné, ale dosáhnete toho, že musíte zadat své hodnoty pouze jednou.
-
Druhý vybere CTE
id
ztbl
pokud "řádek" existuje. -
Třetí vložky CTE i "řádek" do
tbl
pokud (a pouze pokud) neexistuje, vracíid
. -
Poslední
SELECT
vrátíid
. Přidal jsem sloupecsrc
označující „zdroj“ – zda „řádek“ dříve existoval aid
pochází z SELECT, nebo byl "řádek" nový, stejně jakoid
. -
Tato verze by měla být co nejrychlejší, protože nepotřebuje další SELECT z
tbl
a místo toho používá CTE.
Aby to bylo bezpečné proti možným závodním podmínkám v prostředí s více uživateli:
Také pro aktualizované techniky pomocí nového UPSERT v Postgres 9.5 nebo později:
- Je SELECT nebo INSERT ve funkci náchylný k závodům?