Това е повтарящият се проблем на SELECT or INSERT
, свързан с (но различен от) UPSERT. Новата функционалност UPSERT в Postgres 9.5 все още е важна.
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO UPDATE
SET name = NULL
WHERE FALSE -- never executed, but locks the row
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;
По този начин всъщност не пишете нова версия на ред без нужда.
Въпреки това , все още има малък ъглов калъф за състояние на състезание . Едновременните транзакции може да са добавили конфликтен ред, който все още не се вижда в същото изявление. След това INSERT
и SELECT
излизат празни.
Правилно решение за едноредов UPSERT:
- Изберете или INSERT във функция предразположени ли са условия на състезание?
Общи решения за групово UPSERT:
- Как да използвам RETURNING с ON CONFLICT в PostgreSQL?
Без едновременно натоварване на запис
Ако едновременното записване (от друга сесия) не е възможно, не е необходимо да заключвате реда и можете да опростите:
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO NOTHING -- no lock needed
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;