You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL累计求和出现多行值相同的问题及原因解析

窗口函数累计和的框架问题解答

问题详情

数据表结构

Candidates表:

employee_idexperiencesalary
1Junior10000
9Junior15000
2Senior20000
11Senior16000
13Senior50000
4Junior40000

需求

按experience和salary排序,计算salary的逐行累计和。

初始代码

SELECT employee_id, experience, salary, SUM(salary) OVER(ORDER BY experience, salary) as cumsum
FROM Candidates

期望输出

employee_idexperiencesalarycumsum
11Senior1600016000
2Senior2000036000
13Senior5000086000
1Junior1000096000
9Junior15000111000
4Junior40000151000

实际输出

employee_idexperiencesalarycumsum
11Senior1600016000
2Senior2000036000
13Senior50000151000
1Junior10000151000
9Junior15000151000
4Junior40000151000

补充说明

salary字段的值是唯一的。

修正后代码

添加ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW后代码正常运行:

SELECT employee_id, experience, salary, SUM(salary) OVER(ORDER BY experience, salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumsum
FROM Candidates

原因解释

问题出在窗口函数的默认框架规则上:

  • 当仅在OVER()子句中指定ORDER BY而不声明窗口框架时,多数SQL数据库会默认使用RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW作为窗口范围。
  • RANGE框架是基于ORDER BY列的逻辑值范围确定窗口:它会包含所有ORDER BY列组合值小于等于当前行值的行。但你的场景中,数据库对experience字符串的排序逻辑出现了预期外判断,导致RANGE框架错误地将所有行纳入当前窗口,直接计算了所有salary的总和。
  • 而ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW是基于物理行位置的框架:它明确指定窗口包含排序后结果集的第一行到当前行的所有行,完全按行顺序逐行累计,不受ORDER BY列的逻辑值判断影响,因此能得到预期的逐行累计结果。

内容的提问来源于stack exchange,提问作者MTWinner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 02:18:09