位置:首页 > SQL > 如何使用 SQL 窗口函数计算累计总额?

如何使用 SQL 窗口函数计算累计总额?

时间:2026-08-24  |  作者:游戏探长  |  阅读:0

累计总额是按指定列顺序逐行累加的值,必须保留原始行数;不能用GROUP BY,因其会压缩行数、丢失行序,无法生成每行对应的“截至当前”的动态和。

如何使用SQL窗口函数计算累计总额?

什么是累计总额,为什么不能用 GROUP BY

累计总额(running total),就是按照某一列的顺序,依次逐行累加得到的值。举个例子,比如按照日期,一天天地累加销售额。它和分组聚合可是不一样的哦:GROUP BY会把行数压缩掉,而累计总额必须要保持原始的行数,每一行都得有一个结果。要是强行用SUM() + GROUP BY,那是没办法实现累计总额的效果的——它只能算出每个分组的总和,而不是“到当前行为止的和”。

用 SUM() OVER() 实现基础累计和

核心就是 SUM(column) OVER (ORDER BY key)。窗口函数不改变行数,OVER 子句定义“从哪开始、按什么顺序、累加到哪”。常见写法:

  • SUM(sales) OVER (ORDER BY date):按 date 升序,从第一行累加到当前行
  • SUM(sales) OVER (PARTITION BY region ORDER BY date):先按 region 分组,组内再按 date 累加
  • 默认帧范围是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,不用显式写,但要知道它隐含了“从头到当前”

示例(PostgreSQL/MySQL 8.0+/SQL Server):

SELECT date, sales,
 SUM(sales) OVER (ORDER BY date) AS running_total
FROM sales_data;

ORDER BY 缺失或重复时的结果不可靠

倘若没有 ORDER BYSUM() OVER() 的表现是不确定的。多数引擎会按照物理存储顺序进行累加,但这个顺序并非一成不变,换表、VACUUM、INSERT顺序改变等都有可能致使结果发生变化。更为严重的是,当排序键存在重复情况(例如多笔同一天的订单)时,数据库有可能随意打乱这些行的相对顺序,进而导致累计值在重复键之间出现“忽高忽低”的现象。

解决方法:

  • 始终显式指定 ORDER BY,且排序字段要能唯一确定行序(如加 id 作为第二排序条件:ORDER BY date, id
  • 避免用 ORDER BY created_at 这类可能毫秒级重复的字段单独排序
  • 如果业务允许,可在源头加自增 seq 字段专用于排序

性能注意:大表上 ORDER BY 可能触发排序临时文件

OVER (ORDER BY ...) 本质需要对窗口数据排序。若排序字段无索引,100 万行以上就可能明显变慢,甚至因内存不足写磁盘临时文件。这不是语法问题,而是执行计划层面的开销。

优化建议:

  • 确保 ORDER BY 字段有索引(复合索引优先覆盖 PARTITION BY + ORDER BY 字段)
  • 避免在 WHERE 条件过滤前计算全表累计和;先 WHEREOVER(子查询或 CTE)
  • MySQL 8.0 中,ORDER BY 后跟 ROWS UNBOUNDED PRECEDING 不影响性能,但加 RANGE 帧可能更慢(需值比较)

累计总额看着简单,但顺序依赖、排序稳定性、执行计划这三点,任何一个没踩准,查出来的数字就可能白天对、晚上错。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多