Select
MERGE/UPSERT 的 SELECT 或 set-returning 版本?
我正在學習
MERGE
或UPSERT
(UPDATE
+INSERT
),根據維基百科,它具有以下形式:MERGE INTO tablename USING table_reference ON (condition) WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...] WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...]);
, 和:
如果源中的 ON 欄位與目標中的 ON 欄位匹配,則更新
如果源中的 ON 欄位與目標中的 ON 欄位不匹配,則 INSERT
我想知道是否有一個
SELECT
版本(沒有副作用)返回更新後的目標表的可能結果而不實際更改目標表?以 PostgreSQL 9.5 的
INSERT INTO ... ON CONFLICT [ conflict_target ] conflict_action
聲明(在維基百科中指出)為例。給定一個目標表distributors
和一個更新表distributors_upd
如下:DROP TABLE IF EXISTS distributors; DROP TABLE IF EXISTS distributors_upd; CREATE TABLE distributors (did INTEGER PRIMARY KEY, dname VARCHAR); INSERT INTO distributors VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc'); CREATE TABLE distributors_upd (did INTEGER PRIMARY KEY, dname VARCHAR); INSERT INTO distributors_upd VALUES (5, 'Gizmo Transglobal*');
是否有一個有效的查詢來獲得結果
UPSERT
而不實際更改目標表distributors
?我試圖模仿這種效果:
WITH distributors_updated AS ( INSERT INTO distributors (did, dname) (TABLE distributors_upd) ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname RETURNING * ) --SELECT * FROM distributors; SELECT * FROM distributors_updated;
最後兩行都沒有給出預期的結果:
did | dname -----+--------------------------- 6 | Associated Computing, Inc 5 | Gizmo Transglobal*
第一個
... SELECT * FROM distributors
顯示原始表格(按設計)。-----+--------------------------- 5 | Gizmo Transglobal 6 | Associated Computing, Inc (2 rows)
第二個
... SELECT * FROM distributors_updated
僅顯示更改行。-----+-------------------- 5 | Gizmo Transglobal* (1 row)
的內容以
distributors
任何一種方式更改。是否有一個有效的查詢返回“合併”/“聯合”而不實際更改目標distributors
?
如果您想在不實際執行的情況下查找“UPSERT”的結果,可以使用以下命令執行查詢
FULL JOIN
:SELECT did, COALESCE(s.dname, t.dname) AS dname -- in case of conflict, -- give precedence to source table FROM distributors AS t FULL JOIN distributors_upd AS s USING (did) ;
在**dbfiddle.uk**進行測試(感謝 McNets進行設置)
將通過合併更新衝突的列將在
COALESCE()
函式中首先具有源列,然後是目標列。如果更新更複雜,則必須使用更複雜的COALESCE()
orCASE
表達式。例子:ON CONFLICT UPDATE SET counter = counter + EXCLUDED.counter
會變成
SELECT COALESCE(t.counter + s.counter, t.counter, s.counter) AS counter