Đây là sự cố lặp lại của SELECT or INSERT
, liên quan đến (nhưng khác với) một UPSERT. Chức năng UPSERT mới trong Postgres 9.5 vẫn là một công cụ.
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;
Bằng cách này, bạn không thực sự viết một phiên bản hàng mới mà không cần.
Tuy nhiên , vẫn còn một trường hợp góc nhỏ cho điều kiện cuộc đua . Các giao dịch đồng thời có thể đã thêm một hàng xung đột, hàng này chưa được hiển thị trong cùng một câu lệnh. Sau đó, INSERT
và SELECT
trống rỗng.
Giải pháp thích hợp cho UPSERT một hàng:
- CHỌN hoặc CHÈN trong một hàm có nguy cơ gặp phải các điều kiện về chủng tộc không?
Các giải pháp chung cho UPSERT số lượng lớn:
- Cách sử dụng RETURNING với ON CONFLICT trong PostgreSQL?
Không có tải ghi đồng thời
Nếu không thể ghi đồng thời (từ một phiên khác), bạn không cần khóa hàng và có thể đơn giản hóa:
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;