PostgreSQL中能否用ROW类型变量简化ON CONFLICT DO UPDATE语句?
在PostgreSQL 14中实现ON CONFLICT时批量更新所有列的简化写法
PostgreSQL 14并不支持你尝试的SET (*) = ROW(_context.*)这种直接批量更新所有列的语法,但有两种简化方式能帮你实现需求,不用手动逐个枚举列名:
方案1:用表别名结合excluded虚拟行
这是最简洁的写法,直接利用PostgreSQL提供的excluded虚拟行(它代表原本要插入的那条数据),配合表别名就能一次性更新所有列:
INSERT INTO audit.etl_failed_execution_contexts AS efc VALUES (_context.*) ON CONFLICT (correlation_id) DO UPDATE SET efc = excluded;
只要_context的结构和目标表完全匹配(列数、顺序、数据类型一致),这个写法就能正常工作。就算后续表结构新增了列,也不用修改这条语句,维护起来很省心。另外因为触发冲突的correlation_id在excluded和现有行里是同一个值,更新后不会有变化,不用担心破坏约束。
方案2:自动生成列列表(适合需要显式列的场景)
如果偏好显式列出列名,但不想手动输入所有字段,可以先查询系统表自动生成列列表:
SELECT string_agg(column_name, ', ') FROM information_schema.columns WHERE table_schema = 'audit' AND table_name = 'etl_failed_execution_contexts';
把查询结果复制到下面的语句里,就能用行构造函数批量更新:
INSERT INTO audit.etl_failed_execution_contexts VALUES (_context.*) ON CONFLICT (correlation_id) DO UPDATE SET (col1, col2, col3, ...) = ROW(excluded.col1, excluded.col2, excluded.col3, ...);
这个写法需要每次表结构变更后重新生成列列表,适合对语法严谨性有要求的场景。
内容的提问来源于stack exchange,提问作者quickdraw
相关产品推荐
相关产品推荐

