Решение в един SQL израз. Изисква PostgreSQL 8.4 или по-късно обаче.
Помислете за следната демонстрация:
Тестова настройка:
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:
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;
-
ПървиятCTE v не е строго необходимо, но постига това, че трябва да въведете своите стойности само веднъж.
-
Вторият CTE s избира
id
отtbl
ако "редът" съществува. -
Третият CTE i вложки "реда" в
tbl
ако (и само ако) не съществува, връщайкиid
. -
Крайният
SELECT
връщаid
. Добавих колонаsrc
посочване на "източника" - дали "редът" е съществувал преди иid
идва от SELECT или "редът" е нов, както иid
. -
Тази версия трябва да е възможно най-бърза, тъй като не се нуждае от допълнителен SELECT от
tbl
и вместо това използва CTEs.
За да направите това безопасно срещу възможни условия на състезание в среда с множество потребители:
Също така за актуализирани техники, използващи новия UPSERT в Postgres 9.5 или по-късно:
- Изберете или INSERT във функция предразположени ли са условия на състезание?