Một giải pháp trong một câu lệnh SQL duy nhất. Yêu cầu PostgreSQL 8.4 hoặc mới hơn.
Hãy xem xét bản trình diễn sau:
Thiết lập thử nghiệm:
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');
Lệnh 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 đầu tiên không hoàn toàn cần thiết, nhưng đạt được rằng bạn phải nhập giá trị của mình chỉ một lần.
-
CTE thứ hai được chọn
id
từtbl
nếu "hàng" tồn tại. -
CTE thứ ba mà tôi chèn "hàng" thành
tbl
nếu (và chỉ khi) nó không tồn tại, trả vềid
. -
SELECT
cuối cùng trả vềid
. Tôi đã thêm một cộtsrc
cho biết "nguồn" - liệu "hàng" đã tồn tại trước hay chưa vàid
đến từ một CHỌN hoặc "hàng" mới vàid
cũng vậy . -
Phiên bản này phải nhanh nhất có thể vì nó không cần thêm SELECT từ
tbl
và sử dụng CTE thay thế.
Để làm cho điều này an toàn trước các điều kiện chạy đua có thể xảy ra trong môi trường nhiều người dùng:
Cũng để biết các kỹ thuật được cập nhật bằng cách sử dụng UPSERT mới trong Postgres 9.5 trở lên:
- 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?