添加对 MERGE SQL 命令的支持。MERGE 执行修改目标表中的行的操作,使用源表或查询。 MERGE 提供了一条 SQL 语句,可以有条件地 INSERT/UPDATE/DELETE 行 - 否则会执行的任务需要多个 PL 语句。例如:
MERGE INTO target AS t
USING source AS s
ON t.tid = s.sid
WHEN MATCHED AND t.balance > s.delta THEN
UPDATE SET balance = t.balance - s.delta
WHEN MATCHED THEN
DELETE
WHEN NOT MATCHED AND s.delta > 0 THEN
INSERT VALUES (s.sid, s.delta)
WHEN NOT MATCHED THEN
DO NOTHING;
MERGE 适用于常规表、分区表和继承层次结构,包括列和行安全实施,以及支持行和语句触发器以及其中的转换表。
MERGE 针对 OLTP 进行了优化,并且可以参数化,但也用于大规模 ETL/ELT。 MERGE 不打算优先应用到 INSERT、UPDATE 或 DELETE 的单个 SQL 命令,因为那里是一些开销。可以从 PL/pgSQL 使用 MERGE。
MERGE 不支持以可更新视图或外部表为目标,并且也不允许使用 RETURNING 子句。这些限制很可能花大力才可以修复。也不支持重写规则,但不清楚我们是否愿意支持重写规则。
2015 年,PG 10 我们获得了 INSERT … ON CONFLICT DO …。
然后,在 2018 年,PG 11我们几乎获得了 MERGE功能,但是中途出现了问题,补丁被恢复了。
现在,四年过去了,似乎是时候到了。
现在,让我们看看在一些简单的情况下这些语法如何。
$ create table test (
id int8 generated always as identity,
username text not null unique,
touch_count int4 not null default 0,
primary key (id)
);
CREATE TABLE
现在,让我们编写将插入或更新的查询,具体取决于给定用户是否存在:
$ merge into test t
using (values ('depesz')) as i(un)
on t.username = i.un
when matched then
update set touch_count = touch_count + 1
when not matched then
insert (username, touch_count) values (i.un, 1);
MERGE 1
现在我插入了 使用 ‘depesz’,之前表格很清晰。所以表格的内容是……:
$ select * from test;
id | username | touch_count
----+----------+-------------
1 | depesz | 1
(1 row)
看起来不错。如果我再次尝试此合并会发生什么?
$ merge into test t
using (values ('depesz')) as i(un)
on t.username = i.un
when matched then
update set touch_count = touch_count + 1
when not matched then
insert (username, touch_count) values (i.un, 1);
MERGE 1
$ select * from test;
id | username | touch_count
----+----------+-------------
1 | depesz | 2
(1 row)
很酷的部分是当合并中的 WHEN 子句可以进行更多比较。你就会拥有更多。
例如,假设某个用户被“插入”超过 3 次,它将被删除:
$ merge into test t
using (values ('depesz')) as i(un)
on t.username = i.un
when matched and touch_count < 3 then
update set touch_count = touch_count + 1
when matched then
delete
when not matched then
insert (username, touch_count) values (i.un, 1);
MERGE 1
$ select * from test;
id | username | touch_count
----+----------+-------------
1 | depesz | 3
(1 row)
$ merge into test t
using (values ('depesz')) as i(un)
on t.username = i.un
when matched and touch_count < 3 then
update set touch_count = touch_count + 1
when matched then
delete
when not matched then
insert (username, touch_count) values (i.un, 1);
MERGE 1
$ select * from test;
id | username | touch_count
----+----------+-------------
(0 rows)
第一次合并效果很好,将 touch_count 增加到 3。第二次看到 touch_count 已经为 3,因此它删除了该行!
有一个重要的缺失特征(在我看来)——缺乏RETURNING。




