【问题标题】:Merge two rows in same table while summing a column在对列求和时合并同一表中的两行
【发布时间】:2023-02-25 03:07:49
【问题描述】:

冒着不完全理解 PostgresQL 的风险,这里是:

我有一个名为work 的表。

CREATE TABLE work(
    name character varying(40) NOT NULL,
    round bigint NOT NULL,
    amount bigint,

    PRIMARY KEY (name, round)
)

添加新行,其中每个名称可以有多个轮次。第 0 轮在我的申请中具有特殊意义。

有时,特定的轮次需要合并回第 0 轮。第 0 轮可能存在,但也可能不存在。所以,有了以下数据:

name round amount
1 0 300
1 3 100
2 0 500
2 3 1500
1 6 200
1 9 200
2 6 50
2 9 75

(订购不是为了让它更清楚)

第 3 轮的所有行需要与第 0 轮的行合并,求和并保持其他轮 (6、9) 完整。最后,需要从表中删除所有具有 round 3 的行,只留下

name round amount
1 0 400
2 0 2000
1 6 200
1 9 200
2 6 50
2 9 75

明确地说,我不需要 SELECT 语句,但我需要将其写入数据库。

我想到了什么

WITH round_to_move AS (
    SELECT name, round, amount 
    FROM work 
    WHERE name = $1 AND round = $2
)
INSERT INTO work (name, round, work)
SELECT name, 0, amount, work 
FROM round_to_move
ON CONFLICT (name, round)
DO UPDATE SET amount = work.amount + EXCLUDED.amount

但这不会删除现有行。

所以,我正在寻找的是一种带有 GROUP BY 和 SUM() 的 UPDATE 语句,但我无法弄清楚。

【问题讨论】:

  • 我没有看到您的查询将如何工作:1) 我没有看到 work 列来自哪里? 2) SELECT name, 0, amount, work... 1 是您尝试插入到三列(name, round, work) 中的四个值。

标签: postgresql


【解决方案1】:

进行 INSERT 另一个 CTE 查询,然后在末尾进行 DELETE:

CREATE TABLE work(
    name character varying(40) NOT NULL,
    round bigint NOT NULL,
    amount bigint,
    PRIMARY KEY (name, round)
);
INSERT INTO work values (1,0 ,300),
(1 ,3 ,100),
(2 ,0 ,500),
(2 ,3 ,1500),
(1 ,6 ,200),
(1 ,9 ,200),
(2 ,6 ,50),
(2 ,9 ,75);

 select * from work;
 name | round | amount 
------+-------+--------
 1    |     0 |    300
 1    |     3 |    100
 2    |     0 |    500
 2    |     3 |   1500
 1    |     6 |    200
 1    |     9 |    200
 2    |     6 |     50
 2    |     9 |     75

WITH round_to_move AS (
    SELECT name, round, amount 
    FROM work 
    WHERE name = '1' AND round = 3
),
ins as (INSERT INTO work (name, round, amount)
SELECT name, 0, amount
FROM round_to_move
ON CONFLICT (name, round)
DO UPDATE SET amount = work.amount::integer + EXCLUDED.amount)
delete from 
   work using round_to_move 
where 
   work.name = round_to_move.name 
and 
   work.round = round_to_move.round;

select * from work; 
 name | round | amount 
------+-------+--------
 2    |     0 |    500
 2    |     3 |   1500
 1    |     6 |    200
 1    |     9 |    200
 2    |     6 |     50
 2    |     9 |     75
 1    |     0 |    400


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2013-11-13
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多