PostgreSQL实现指定Round合并到Round 0并求和Amount列
解决方案
你可以通过WITH子句结合INSERT ... ON CONFLICT和DELETE完成合并与删除操作,整个操作是原子性的(要么全部执行成功,要么全部回滚),完全满足你的需求:
场景1:合并所有name的指定round到Round 0
如果需要将所有name下某个特定round(比如示例中的3)的数据合并到Round 0,并删除该round的所有行,使用以下语句:
WITH merge_round AS ( -- 将目标round的amount合并到对应name的Round 0(存在则累加,不存在则插入) INSERT INTO work (name, round, amount) SELECT name, 0, SUM(amount) FROM work WHERE round = $2 -- $2替换为你要合并的round值,比如3 GROUP BY name ON CONFLICT (name, round) DO UPDATE SET amount = work.amount + EXCLUDED.amount ) -- 删除原round的所有行 DELETE FROM work WHERE round = $2;
场景2:合并单个name的指定round到Round 0
如果只需要处理某个特定name(比如name='1')的指定round,使用以下语句:
WITH merge_round AS ( INSERT INTO work (name, round, amount) SELECT name, 0, amount FROM work WHERE name = $1 AND round = $2 -- $1是目标name,$2是要合并的round值 ON CONFLICT (name, round) DO UPDATE SET amount = work.amount + EXCLUDED.amount ) DELETE FROM work WHERE name = $1 AND round = $2;
关键说明
- INSERT ... ON CONFLICT:利用主键
(name, round)的唯一性,自动处理两种情况:- 如果该name的Round 0已存在:累加原amount和目标round的amount
- 如果该name的Round 0不存在:直接插入新行,amount为目标round的数值
- WITH子句:将合并操作和删除操作放在同一个原子事务中,避免中间状态的数据不一致
- 修正了你原语句的错误:原语句中
INSERT INTO work (name, round, work)列名写错,应该是amount而非work
示例验证
以你提供的测试数据为例,当$2=3时执行场景1的语句:
- 首先,name='1'的Round 0 amount从300变为300+100=400;name='2'的Round 0 amount从500变为500+1500=2000
- 随后删除所有
round=3的行,最终得到你期望的结果
内容的提问来源于stack exchange,提问作者n41r0j
相关产品推荐
相关产品推荐

