在 MySQL 中创建累积和列

Posted

技术标签:

【中文标题】在 MySQL 中创建累积和列【英文标题】:Create a Cumulative Sum Column in MySQL 【发布时间】:2011-02-03 13:39:50 【问题描述】:

我有一个如下所示的表格:

id   count
1    100
2    50
3    10

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

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

是否有一个 mysql 更新语句可以轻松做到这一点?完成此任务的最佳方法是什么?

【问题讨论】:

【参考方案1】:

使用相关查询:


  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 命令的情况下声明变量。 对于任何子查询/派生表/内联视图,MySQL 都需要表别名 r

注意事项:

MySQL 特定的;不能移植到其他数据库 ORDER BY 很重要;它确保顺序与 OP 匹配,并且可以对更复杂的变量使用产生更大的影响(即:伪 ROW_NUMBER/RANK 功能,这是 MySQL 所缺乏的)

【讨论】:

我会在主查询中添加“ORDER BY t.id ASC”,以确保它始终有效 我的第一个想法也是添加 ORDER BY。但这无关紧要。直到加法变成非关联,至少:) @OMG Poines:我认为您需要在变量示例的JOIN (SELECT @running_total := 0) 部分中使用SELECT 对于“使用相关查询”,您的表 x 来自哪里? 除非内部发生优化,否则相关子查询相当于在 O(N^2) 时间内执行的三角连接——它不会扩展。【参考方案2】:

如果性能是一个问题,您可以使用 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;

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

【讨论】:

使用交叉连接来定义变量而不需要使用SET 我的表有 3600 万条记录,所以这对加快速度非常有帮助! 请注意,按累积和排序可能会强制进行全表扫描。 这确实有效,而且看起来相当快;有什么建议可以扩展为在一组中进行累积和吗?例如按Name 或类似方法分组,然后仅对同名记录进行累积求和 @zaitsman 您可以将其用作子查询;在外部查询中,按您想要的任何内容进行分组,然后使用 MAX() MySQL 函数获取为组内记录计算的正确累积汇总(最后一个汇总)。【参考方案3】:

MySQL 8.0/MariaDB 支持窗口化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<>fiddle

【讨论】:

我正在寻找使用windows函数的累积和。谢谢。【参考方案4】:
UPDATE t
SET cumulative_sum = (
 SELECT SUM(x.count)
 FROM t x
 WHERE x.id <= t.id
)

【讨论】:

虽然 OP 确实要求更新,但这是非规范化的,可能不方便正确维护。【参考方案5】:
select Id, Count, @total := @total + Count as cumulative_sum
from YourTable, (Select @total := 0) as total ;

【讨论】:

请解释一下你的答案 答案很有效,而且是一个班轮。它还在选择开始时将变量初始化/重置为零。【参考方案6】:

示例查询

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

【讨论】:

【参考方案7】:

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

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;
|

我没有测试过这个

【讨论】:

【参考方案8】:

从tableName中选择id,count,sum(count)over(order by count desc)作为cumulative_sum;

我在 count 列上使用了 sum 聚合函数,然后使用了 over 子句。它单独总结每一行。第一行将是 100。第二行将是 100+50。第三行是 100+50+10,以此类推。所以基本上每一行都是它和前面所有行的总和,最后一行是所有行的总和。所以看这个的方式是每一行都是ID小于等于自身的数量之和。

【讨论】:

虽然这可能会解决问题,但最好稍微解释一下,以便其他人受益:) 这不是一个共同相关的子查询,也不是一个子查询...共同相关的子查询遵循SELECT ...., (SELECT .... FROM table2 WHERE table2.id = table1.id ) FROM table1 你所拥有的是一个窗口查询..【参考方案9】:
  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

【讨论】:

添加了一些逐步了解最终查询的内容

以上是关于在 MySQL 中创建累积和列的主要内容,如果未能解决你的问题,请参考以下文章

使用 Highcharts 从包含单个降雨数据的系列中创建响应式累积降雨图

在 R 中创建累积步骤图

当我尝试使用文件维度作为行和列在 C 中创建矩阵时,为啥会出现错误?

在 swing 中创建运行时 jtable

想通过以文本格式保留所有行和列来在 C# 中创建 excel 文件

如何在 NativeScript 中创建具有动态行数和列数的表?