PostgreSQL中ON CONFLICT DO NOTHING时如何返回对应行?
解决PostgreSQL INSERT ON CONFLICT时始终返回行的问题
针对你的需求,在PostgreSQL 17.5中可以通过两种方式实现无论冲突是否触发都返回完整行的效果:
方案1:利用ON CONFLICT DO UPDATE(无实际修改)
通过指定冲突的唯一约束列,执行一个无实际数据变更的UPDATE操作,这样RETURNING子句会在冲突时返回现有行,插入成功时返回新行:
INSERT INTO product (name, unit, standard_code) VALUES ('test111', 'BOX', 'ISO-8601') ON CONFLICT (name, unit, standard_code) DO UPDATE SET name = EXCLUDED.name -- 设置为原值,无实际数据修改 RETURNING *;
说明
- 这里明确指定冲突的唯一约束列
(name, unit, standard_code),对应表中定义的uq_product_name唯一约束 EXCLUDED指代插入语句中准备插入的行,设置name = EXCLUDED.name不会改变现有数据,但会触发RETURNING返回冲突行
方案2:使用WITH子句结合UNION ALL
先尝试插入,若插入无返回结果(触发冲突),则查询现有行:
WITH inserted AS ( INSERT INTO product (name, unit, standard_code) VALUES ('test111', 'BOX', 'ISO-8601') ON CONFLICT DO NOTHING RETURNING * ) SELECT * FROM inserted UNION ALL SELECT * FROM product WHERE (name, unit, standard_code) = ('test111', 'BOX', 'ISO-8601') AND NOT EXISTS (SELECT 1 FROM inserted);
说明
insertedCTE执行原插入逻辑,返回新插入的行(无冲突时)- 后续通过
UNION ALL组合结果:若inserted为空(冲突触发),则查询现有行;否则只返回插入的行
两种方案中,方案1性能更优,仅需一次SQL执行;方案2逻辑更直观,不会产生任何更新操作(即使是无意义的)。
内容的提问来源于stack exchange,提问作者Aleksei Khatkevich
相关产品推荐
相关产品推荐

