Postgres 18:RETURNING子句中的OLD和NEW行
本次发布新增功能:在INSERT、UPDATE、DELETE和MERGE命令的RETURNING子句中,可同时访问旧值(OLD)和新值(NEW)。
Postgres 18 今日发布。在异步I/O和UUIDv7支持等头条功能下方,我们发现了这项实用的小改进:
本次发布新增功能:在INSERT、UPDATE、DELETE和MERGE命令的RETURNING子句中,可同时访问旧值(OLD)和新值(NEW)。
虽然不像异步I/O那样具有颠覆性,但这确实是那些在特定场景下不可或缺的小功能之一。
以下通过UPDATE操作获取所有新旧值的简易演示:
UPDATE fruit
SET quantity = 300
WHERE item = 'Apples'
RETURNING OLD.*, NEW.*;
id | item | quantity | id | item | quantity
----+--------+----------+----+--------+----------
5 | Apples | 200 | 5 | Apples | 300
(1 row)
利用OLD检测更新插入操作中的新行
假设我们正在执行upsert操作,需要区分RETURNING返回的行是新插入还是更新的现有行。虽然以前也能实现,但依赖于对xmax = 0的反直觉检查(见下文最后一行):
INSERT INTO webhook (
id,
data
) VALUES (
@id,
@data
)
ON CONFLICT (id)
DO UPDATE SET id = webhook.id -- force upsert to return a row
RETURNING webhook.*,
(xmax = 0) AS is_new;
该语句依赖于Postgres锁机制实现的特性——新插入行会将xmax设为零(详见完整原理说明)。虽然有效,但并非API的保证行为,随时可能变更。
在 Postgres 18 中,我们可以重构上述实现,使其更易于理解且不依赖具体实现细节。实现也很简单——只需在返回子句中检查 OLD 是否为空:
INSERT INTO webhook (
id,
data
) VALUES (
@id,
@data
)
ON CONFLICT (id)
DO UPDATE SET id = webhook.id -- force upsert to return a row
RETURNING webhook.*,
(OLD IS NULL)::boolean AS is_new;
访问 OLD 和 NEW 无疑还有许多其他实用场景,但这个示例能让我们立即改进 18 版之前的代码。
你也许感兴趣的:
- 使用 PostgreSQL 18 实现即时数据库克隆
- 一切皆可Postgres
- Postgres 17 与 18 版本性能对比
- 探索 PostgreSQL 18 的全新 UUIDv7 支持
- 全面解读 PostgreSQL 18 新功能
- UUIDv7 登陆 PostgreSQL 18
- PostgreSQL 18 正式发布!
- 【外评】PostgreSQL 社区讨论 ALTER SYSTEM 命令
- 【译文】我们如何在 11 秒停机时间内迁移 PostgreSQL 数据库
- 分布式 PostgreSQL 基准测试:Azure Cosmos DB、CockroachDB 和 YugabyteDB

你对本文的反应是: