mydb=# INSERTINTO source VALUES (4, 40); INSERT01 mydb=# INSERTINTO source VALUES (3, 20); INSERT01 mydb=# INSERTINTO source VALUES (2, 5); INSERT01 mydb=# select * from target orderby tid; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3rows) mydb=# select * from source orderby sid; sid | delta -----+------- 2 | 5 3 | 20 4 | 40 (3rows) mydb=# mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# UPDATESET balance = 0; MERGE 2 mydb=*# SELECT * FROM target ORDERBY tid; tid | balance -----+--------- 1 | 10 2 | 0 3 | 0 (3rows) mydb=*# ROLLBACK; ROLLBACK mydb=# mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# DELETE; MERGE 2 mydb=*# SELECT * FROM target ORDERBY tid; tid | balance -----+--------- 1 | 10 (1row) mydb=*# ROLLBACK; ROLLBACK mydb=# mydb=# mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# DONOTHING; MERGE 2 mydb=*# SELECT * FROM target ORDERBY tid; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3rows) mydb=*# ROLLBACK; ROLLBACK mydb=# ALTERTABLE target ADDPRIMARY KEY (tid); ALTERTABLE mydb=# INSERTINTO source VALUES (2, 5); INSERT01 mydb=# SELECT * FROM source ORDERBY sid; sid | delta -----+------- 2 | 5 2 | 5 3 | 20 4 | 40 (4rows) mydb=# SELECT * FROM target ORDERBY tid; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3rows) mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# UPDATESET balance = 0; ERROR: MERGE command cannot affect row a second time HINT: Ensure that not more than one source row matches any one target row. mydb=!# ROLLBACK; ROLLBACK mydb=# mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# UPDATESET balance = t.balance + s.delta; MERGE 2 mydb=*# SELECT * FROM target ORDERBY tid; tid | balance -----+--------- 1 | 10 2 | 25 3 | 50 (3rows) mydb=*# ROLLBACK; ROLLBACK mydb=# BEGIN; BEGIN mydb=*# MERGE INTO target t /* unreachable WHEN clause*/ mydb-*# USING source AS s mydb-*# ON t.tid = s.sid mydb-*# WHEN MATCHED THEN mydb-*# DELETE mydb-*# WHEN MATCHED AND s.delta > 0THEN mydb-*# UPDATESET balance = t.balance - s.delta; ERROR: unreachable WHEN clause specified after unconditional WHEN clause mydb=!# ROLLBACK; ROLLBACK
限制
target与source不可为同一个表
1 2 3 4 5 6 7
mydb=# MERGE INTO target mydb-# USING target mydb-# ON tid = tid mydb-# WHEN MATCHED THENDONOTHING; ERROR: name "target" specified more than once DETAIL: The nameis used bothas MERGE target tableand data source. mydb=#
不支持视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mydb=# CREATEVIEW tv ASSELECT * FROM target; CREATEVIEW mydb=# select * from tv; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3 rows) mydb=# MERGEINTO tv t mydb-# USING source s mydb-# ON t.tid = s.sid mydb-# WHENNOTMATCHEDTHEN mydb-# INSERT DEFAULT VALUES; ERROR: cannot execute MERGEon relation "tv" DETAIL: This operation isnot supported for views. mydb=# mydb=# DROPVIEW tv; DROPVIEW
不支持物化视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mydb=# CREATEMATERIALIZEDVIEW mv ASSELECT * FROM target; SELECT3 mydb=# select * from mv; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3 rows) mydb=# MERGEINTO mv t mydb-# USING source s mydb-# ON t.tid = s.sid mydb-# WHENNOTMATCHEDTHEN mydb-# INSERT DEFAULT VALUES; ERROR: cannot execute MERGEon relation "mv" DETAIL: This operation isnot supported formaterialized views. mydb=# mydb=# DROPMATERIALIZEDVIEW mv; DROPMATERIALIZEDVIEW
mydb=# show port; port ------ 5557 (1 row) mydb=# create server s1 foreign data wrapper postgres_fdw OPTIONS (host 'localhost', port '5557', dbname 'mydb'); CREATE SERVER mydb=# mydb=# select user; user ---------- postgres (1 row) mydb=# create user mapping for postgres SERVER s1 OPTIONS ( user 'postgres' ); CREATE USER MAPPING mydb=# mydb=# mydb=# create foreign table target_ft (tid int, balance int) server s1 options (schema_name 'public', table_name 'target'); CREATE FOREIGN TABLE mydb=# create foreign table source_ft (sid int, delta int) server s1 options (schema_name 'public', table_name 'source'); CREATE FOREIGN TABLE mydb=# select * from target_ft; tid | balance -----+--------- 1 | 10 2 | 20 3 | 30 (3 rows) mydb=# select * from source_ft; sid | delta -----+------- (0 rows) mydb=# begin; MERGE INTO target t USING source_ft s ON t.tid = s.sid WHEN NOT MATCHED THEN INSERT DEFAULT VALUES; BEGIN MERGE 0 mydb=*# rollback ; ROLLBACK mydb=# mydb=# mydb=# begin; MERGE INTO target_ft t USING source s ON t.tid = s.sid WHEN NOT MATCHED THEN INSERT DEFAULT VALUES; BEGIN ERROR: cannot execute MERGE on relation "target_ft" DETAIL: This operation is not supported for foreign tables. mydb=!# mydb=!# rollback ; ROLLBACK
commit7103ebb7aae8ab8076b7e85f335ceb8fe799097c Author: Alvaro Herrera <alvherre@alvh.no-ip.org> Date: Mon Mar 2816:45:582022 +0200 Add support forMERGESQL command MERGE performs actions that modifyrowsin the target tableusing a sourcetableor query. MERGE provides a single SQLstatement that can conditionally INSERT/UPDATE/DELETErows-- a task that would otherwise require multiple PL statements. For example, MERGEINTO target AS t USINGsourceAS s ON t.tid = s.sid WHENMATCHEDAND t.balance > s.delta THEN UPDATESET balance = t.balance - s.delta WHENMATCHEDTHEN DELETE WHENNOTMATCHEDAND s.delta > 0THEN INSERTVALUES (s.sid, s.delta) WHENNOTMATCHEDTHEN DONOTHING; MERGE works with regular tables, partitioned tablesand inheritance hierarchies, includingcolumnandrowsecurity enforcement, as well as support forrowandstatementtriggersand transition tables therein. MERGEis optimized for OLTP andis parameterizable, though also useful forlarge scale ETL/ELT. MERGEisnot intended to be used in preference to existing single SQL commands forINSERT, UPDATEorDELETE since there issome overhead. MERGE can be used from PL/pgSQL. MERGE does not support targetting updatable views orforeigntables, and RETURNING clauses arenot allowed either. These limitations are likely fixable with sufficient effort. Rewrite rulesare also not supported, but it's not clear that we'd want to support them. Author: Pavan Deolasee <pavan.deolasee@gmail.com> Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Author: Amit Langote <amitlangote09@gmail.com> Author: Simon Riggs <simon.riggs@enterprisedb.com> Reviewed-by: Peter Eisentraut <peter.eisentraut@enterprisedb.com> Reviewed-by: Andres Freund <andres@anarazel.de> (earlier versions) Reviewed-by: Peter Geoghegan <pg@bowt.ie> (earlier versions) Reviewed-by: Robert Haas <robertmhaas@gmail.com> (earlier versions) Reviewed-by: Japin Li <japinli@hotmail.com> Reviewed-by: Justin Pryzby <pryzby@telsasoft.com> Reviewed-by: Tomas Vondra <tomas.vondra@enterprisedb.com> Reviewed-by: Zhihong Yu <zyu@yugabyte.com> Discussion: https://postgr.es/m/CANP8+jKitBSrB7oTgT9CY2i1ObfOt36z0XMraQc+Xrz8QB0nXA@mail.gmail.com Discussion: https://postgr.es/m/CAH2-WzkJdBuxj9PO=2QaO9-3h3xGbQPZ34kJH=HukRekwM-GZg@mail.gmail.com Discussion: https://postgr.es/m/20201231134736.GA25392@alvherre.pgsql