在MySQL中创建累积总和列


73

我有一个看起来像这样的表:

id   count
1    100
2    50
3    10

我想添加一个新列,称为cumulative_sum,因此表如下所示:

id   count  cumulative_sum
1    100    100
2    50     150
3    10     160

是否有可以轻松完成此操作的MySQL更新语句?做到这一点的最佳方法是什么?

Answers:


90

如果性能是一个问题,则可以使用MySQL变量:

set @csum := 0;
update YourTable
set cumulative_sum = (@csum := @csum + count)
order by id;

或者,您可以删除该cumulative_sum列并在每个查询中对其进行计算:

set @csum := 0;
select id, count, (@csum := @csum + count) as cumulative_sum
from YourTable
order by id;

这以运行方式计算运行总和:)


7
使用交叉联接来定义变量,而无需使用SET
OMG Ponies,2010年

我的表有3600万条记录,因此这对于加快速度非常有帮助!
Kirk Ouimet'4

请注意,按cumulative_sum排序可能会强制执行全表扫描。
马特2012年

1
这确实有效,而且看起来很快。有什么建议可以将其扩展为一个小组的累加总和?例如,分组Name或类似,然后仅对具有相同名称的记录进行累计和
zaitsman

@zaitsman您可以将其用作子查询;在外部查询上,根据需要进行分组,然后使用MAX()MySQL函数获取为组内的记录计算的正确的累积摘要(最后一个摘要)。
帕斯卡

105

使用相关查询:


  SELECT t.id,
         t.count,
         (SELECT SUM(x.count)
            FROM TABLE x
           WHERE x.id <= t.id) AS cumulative_sum
    FROM TABLE t
ORDER BY t.id

使用MySQL变量:


  SELECT t.id,
         t.count,
         @running_total := @running_total + t.count AS cumulative_sum
    FROM TABLE t
    JOIN (SELECT @running_total := 0) r
ORDER BY t.id

注意:

  • JOIN (SELECT @running_total := 0) r是一个交叉联接,并允许变量声明而不需要单独的SET命令。
  • r对于任何子查询/派生表/内联视图,MySQL都需要表别名“

注意事项:

  • 特定于MySQL;无法移植到其他数据库
  • ORDER BY重要的是;它确保顺序与OP匹配,并且对于更复杂的变量使用可能具有更大的含义(即MySQL缺少的psuedo ROW_NUMBER / RANK功能)

我会在主要查询中添加“ ORDER BY t.id ASC”,以确保其始终有效
Wacek 2010年

我的第一个想法就是添加ORDER BY。但这无关紧要。直到除了轮流到非关联的,至少:)
Dercsár

@OMG Poines:我认为您需要在变量示例SELECTJOIN (SELECT @running_total := 0)一部分中使用a 。
丹尼尔·瓦萨洛

1
用于“使用相关查询”,您的表x来自哪里?
allan.simon

除非内部没有进行优化,否则相关子查询将等同于在O(N ^ 2)时间内执行的三角连接-这将不会扩展。
Marc L.

18

MySQL 8.0 / MariaDB支持windowed SUM(col) OVER()

SELECT *, SUM(cnt) OVER(ORDER BY id) AS cumulative_sum
FROM tab;

输出:

┌─────┬──────┬────────────────┐
│ id  │ cnt  │ cumulative_sum │
├─────┼──────┼────────────────┤
│  1  │ 100  │            100 │
│  2  │  50  │            150 │
│  3  │  10  │            160 │
└─────┴──────┴────────────────┘

db <>小提琴


1
我正在使用Windows函数寻找累积和。谢谢。
DatabaseCoder

3
UPDATE t
SET cumulative_sum = (
 SELECT SUM(x.count)
 FROM t x
 WHERE x.id <= t.id
)

3
尽管OP确实要求更新,但此操作已被规范化,可能不便于正确维护。
马修·弗拉申

3
select Id, Count, @total := @total + Count as cumulative_sum
from YourTable, (Select @total := 0) as total ;

4
请解释您的答案
Rohit Gupta

答案是有效的,并且是一个班轮。在选择开始时,还将变量初始化/重置为零。
risercostin

2

样品查询

SET @runtot:=0;
SELECT
   q1.d,
   q1.c,
   (@runtot := @runtot + q1.c) AS rt
FROM
   (SELECT
       DAYOFYEAR(date) AS d,
       COUNT(*) AS c
    FROM  orders
    WHERE  hasPaid > 0
    GROUP  BY d
    ORDER  BY d) AS q1

1

您还可以创建一个触发器,该触发器将在每次插入之前计算总和

delimiter |

CREATE TRIGGER calCumluativeSum  BEFORE INSERT ON someTable
  FOR EACH ROW BEGIN

  SET cumulative_sum = (
     SELECT SUM(x.count)
        FROM someTable x
        WHERE x.id <= NEW.id
    )

    set  NEW.cumulative_sum = cumulative_sum;
  END;
|

我还没有测试


1

从tableName中选择id,count,sum(count)over(按count desc排序)作为cumulative_sum;

我在count列上使用了sum聚合函数,然后使用了over子句。它分别汇总每一行。第一行将是100。第二行将是100 + 50。第三行是100 + 50 + 10,依此类推。因此,基本上每一行都是它与之前所有行的总和,最后一行是所有行的总和。因此,查看此问题的方式是每一行是ID小于或等于其自身的数量之和。


2
尽管这可能会解决问题,但最好对其进行一些解释,以使它对其他人有利:)
Tiw

这不是一个联合相关子查询或与此有关的子查询...合作相关子查询遵循 SELECT ...., (SELECT .... FROM table2 WHERE table2.id = table1.id ) FROM table1 你所拥有的是一个窗口查询..
雷蒙德Nijland

0
  select t1.id, t1.count, SUM(t2.count) cumulative_sum
    from table t1 
        join table t2 on t1.id >= t2.id
    group by t1.id, t1.count

一步步:

1-给定下表:

select *
from table t1 
order by t1.id;

id  | count
 1  |  11
 2  |  12   
 3  |  13

2-按组获取信息

select *
from table t1 
    join table t2 on t1.id >= t2.id
order by t1.id, t2.id;

id  | count | id | count
 1  | 11    | 1  |  11

 2  | 12    | 1  |  11
 2  | 12    | 2  |  12

 3  | 13    | 1  |  11
 3  | 13    | 2  |  12
 3  | 13    | 3  |  13

3-步骤3:按t1.id组总和

select t1.id, t1.count, SUM(t2.count) cumulative_sum
from table t1 
    join table t2 on t1.id >= t2.id
group by t1.id, t1.count;


id  | count | cumulative_sum
 1  |  11   |    11
 2  |  12   |    23
 3  |  13   |    36

添加了一些逐步了解最终查询的内容
Flavio_cava
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.