PostgreSQL 15 即将支持 SQL 标准中的 MERGE 语句

Posted 不剪发的Tony老师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL 15 即将支持 SQL 标准中的 MERGE 语句相关的知识,希望对你有一定的参考价值。

早在 2003 年 SQL 标准就支持了 MERGE 语句,它可以基于源表或者查询结果更新目标表中的数据。MERGE 可以在单个语句中实现 INSERT、UPDATE 以及 DELETE 操作。

目前只有 Oracle 和 SQL Server 支持 MERGE 语句,不过即将到来的 PostgreSQL 15 已经确认会增加 MERGE 语句。在此之前,我们可以使用 INSERT … ON CONFLICT DO …. 语句代替该功能。

PostgreSQL 官方文档中已经可以查看 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)
);

下面的查询可以基于指定用户是否存在执行插入或者更新操作:

merge into test t
using (values ('super')) 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

执行以上语句会插入用户 super,查询一下表中的内容:

select * from test;
 id | username | touch_count 
----+----------+-------------
  1 | super    |           1
(1 row)

如果我们再次执行上面的 MERGE 语句:

merge into test t
using (values ('super')) 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 | super    |           2
(1 row)

这次没有插入新的用户,而是更新了已经存在的用户。

MEREG 语句中的 WHEN 子句可以使用复合条件,而且我们可以指定多个 WHEN 子句。例如,假设我们希望用户最多被操作 3 次,超过次数则会被删除:

merge into test t
using (values ('super')) 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 | super    |           3
(1 row)
 
merge into test t
using (values ('super')) 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)

其中第一个 MERGE 语句将 super 用户的 touch_count 增加为 3。第二个 MERGE 语句发现 touch_count 已经到达 3 次,所以删除了该用户。

MERGE 语句支持普通表、分区表以及继承层次结构,包括列级和行级安全增强,以及行级触发器、语句级触发器和触发器中的过渡表。

MERGE 针对 OLTP 进行了优化,支持参数化语句,对于大规模 ETL、ELT 也很有用。不过,MERGE 并不是为了替代已有的 INSERT、UPDATE 或者 DELETE 语句,因为它存在一些额外的开销。

MERGE 可以用于 PL/pgSQL 存储过程。

MERGE 不支持使用可更新视图或者外部表作为目标表,目前也不支持 RETURNING 子句,这些限制可以通过其他方式解决。MERGE 也不支持重写规则。

以上是关于PostgreSQL 15 即将支持 SQL 标准中的 MERGE 语句的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 15 JSON 函数增强

PostgreSQL 15 JSON 函数增强

[译]PostgreSQL-15逻辑复制发布/订阅的两阶段提交

Percona PostgreSQL 11分支即将发布release稳定版

PostgreSQL之SQL函数介绍及实践

PostgreSQL的SQL语句中的双引号引发的问题