CẬP NHẬT (2015-08-20):
Bây giờ có một thi chính thức để xử lý upserts thông qua việc sử dụng ON CONFLICT DO UPDATE
(tài liệu chính thức). Tại thời điểm viết bài này, tính năng này hiện đang nằm trong PostgreSQL 9.5 Alpha 2, có sẵn để tải xuống tại đây: Thư mục nguồn Postgres .
Đây là một ví dụ, giả sử item_id
là Khóa chính của bạn:
INSERT INTO my_table
(item_id, price)
VALUES
(123456, 10.99)
ON
CONFLICT (item_id)
DO UPDATE SET
price = EXCLUDED.price
Bài gốc ...
Đây là một triển khai tôi đã thực hiện khi mong muốn đạt được khả năng hiển thị về việc liệu có chèn hoặc cập nhật hay không.
Định nghĩa của upsert_data
là hợp nhất các giá trị thành một tài nguyên duy nhất, thay vì phải chỉ định giá và item_id hai lần: Một lần cho bản cập nhật, một lần nữa cho phần chèn.
WITH upsert_data AS (
SELECT
'19.99'::numeric(10,2) AS price,
'abcdefg'::character varying AS item_id
),
update_outcome AS (
UPDATE pricing_tbl
SET price = upsert_data.price
FROM upsert_data
WHERE pricing_tbl.item_id = upsert_data.item_id
RETURNING 'update'::text AS action, item_id
),
insert_outcome AS (
INSERT INTO
pricing_tbl
(price, item_id)
SELECT
upsert_data.price AS price,
upsert_data.item_id AS item_id
FROM upsert_data
WHERE NOT EXISTS (SELECT item_id FROM update_outcome LIMIT 1)
RETURNING 'insert'::text AS action, item_id
)
SELECT * FROM update_outcome UNION ALL SELECT * FROM insert_outcome
Nếu bạn không thích sử dụng upsert_data
, đây là một triển khai thay thế:
WITH update_outcome AS (
UPDATE pricing_tbl
SET price = '19.99'
WHERE pricing_tbl.item_id = 'abcdefg'
RETURNING 'update'::text AS action, item_id
),
insert_outcome AS (
INSERT INTO
pricing_tbl
(price, item_id)
SELECT
'19.99' AS price,
'abcdefg' AS item_id
WHERE NOT EXISTS (SELECT item_id FROM update_outcome LIMIT 1)
RETURNING 'insert'::text AS action, item_id
)
SELECT * FROM update_outcome UNION ALL SELECT * FROM insert_outcome