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
idtừtblnếu "hàng" tồn tại. -
CTE thứ ba mà tôi chèn "hàng" thành
tblnếu (và chỉ khi) nó không tồn tại, trả vềid. -
SELECTcuối cùng trả vềid. Tôi đã thêm một cộtsrccho 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àidcũ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ừ
tblvà 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?