如何在MySQL中按id分组计算累计值?修正错误代码
分组计算累计Volume的SQL解决方案
嘿,我来帮你搞定这个分组累计求和的问题!先明确你的数据场景:
你有一张名为temp的数据表:
| id_val | date_val | volume_val |
|---|---|---|
| 1 | 26-Jan-18 | 100 |
| 1 | 25-Jan-18 | 200 |
| 1 | 24-Jan-18 | 300 |
| 1 | 23-Jan-18 | 150 |
| 2 | 26-Jan-18 | 250 |
| 2 | 25-Jan-18 | 350 |
| 2 | 24-Jan-18 | 400 |
| 3 | 23-Jan-18 | 500 |
你想要按id_val分组,按date_val降序(最新日期在前)计算累计的volume_val,目标结果如下:
| id_val | date_val | volume_val | cumulative_volume_val |
|---|---|---|---|
| 1 | 26-Jan-18 | 100 | 100 |
| 1 | 25-Jan-18 | 200 | 300 |
| 1 | 24-Jan-18 | 300 | 600 |
| 1 | 23-Jan-18 | 150 | 750 |
| 2 | 26-Jan-18 | 250 | 250 |
| 2 | 25-Jan-18 | 350 | 600 |
| 2 | 24-Jan-18 | 400 | 1000 |
| 3 | 23-Jan-18 | 500 | 500 |
你之前的代码问题很明确:全局变量@csum没有在每个id_val分组结束后重置,导致所有id的数值一直累加,没法实现分组内的独立累计。下面给你两种可行的改进方案:
方案一:使用窗口函数(MySQL 8.0+ 推荐)
如果你的MySQL版本是8.0及以上,窗口函数是最简洁易维护的方式,直接用SUM() OVER()语法就能实现分组累计:
SELECT id_val, date_val, volume_val, SUM(volume_val) OVER ( PARTITION BY id_val ORDER BY date_val DESC ) AS cumulative_volume_val FROM temp ORDER BY id_val, date_val DESC;
解释:
PARTITION BY id_val:按id_val划分分组,每个组单独计算累计值ORDER BY date_val DESC:每个组内按日期降序排序,从最新日期开始依次累加
方案二:使用变量兼容低版本MySQL
如果你的MySQL版本低于8.0,就需要用变量来实现,核心是在id_val变化时重置累计值:
SELECT id_val, date_val, volume_val, @csum := CASE WHEN @prev_id = id_val THEN @csum + volume_val ELSE volume_val END AS cumulative_volume_val, @prev_id := id_val -- 记录当前id,用于下一行的分组判断 FROM temp, (SELECT @csum := 0, @prev_id := NULL) AS init_vars ORDER BY id_val, date_val DESC;
解释:
- 初始化两个变量:
@csum存储当前累计值,@prev_id存储上一行的id_val - 每一行判断当前
id_val是否和上一行相同:- 相同则继续累加
volume_val到@csum - 不同则把
@csum重置为当前行的volume_val
- 相同则继续累加
- 必须按
id_val和date_val DESC排序,保证分组和累加顺序的正确性
这样就能得到你想要的分组累计结果啦!
内容的提问来源于stack exchange,提问作者john
相关产品推荐
相关产品推荐

