cume_dist是静态分组内小于等于当前行值的行数占比,不随窗口滑动变化;移动累计百分比需用sum() over(... order by ... rows between unbounded preceding and current row)实现。

什么是 CUME_DIST,它和移动累计百分比有关系吗
CUME_DIST 计算的是「小于等于当前行值的行数占总行数的比例」,属于静态分组内整体分布统计,不是移动累计——它不随窗口滑动变化,也不按时间/序号逐行累加。如果你要的是“每条记录截止到当前行为止、该分组内累计占比”,比如销售流水按日期排序后逐日累加占当月总销售额比例,CUME_DIST 无法直接满足。
真正适合移动累计百分比的是 SUM() OVER (...) / SUM() OVER (PARTITION BY ...) 组合,或配合 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 的窗口定义。
-
CUME_DIST返回值范围是 (0, 1],最小非零值为1.0 / 总行数 - 它对重复值返回相同结果(例如两个并列第2名,
CUME_DIST都是 0.6),而移动累计会因顺序不同而不同 - 没有
ORDER BY子句时,CUME_DIST行为未定义(多数数据库报错)
怎么用窗口函数实现真正的移动累计百分比
核心思路:先算分组内逐行累计和,再除以该分组总和。必须显式指定 ORDER BY 来定义“移动”方向,否则累计无意义。
SELECT
category,
sale_date,
amount,
SUM(amount) OVER (
PARTITION BY category
ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumsum_amount,
ROUND(
SUM(amount) OVER (
PARTITION BY category
ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) * 100.0 /
SUM(amount) OVER (PARTITION BY category),
2
) AS cum_pct
FROM sales;
-
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW是关键,漏掉会导致全分组求和而非移动累计 - 分母用
SUM(amount) OVER (PARTITION BY category),不能写成子查询或 CTE,否则失去窗口函数性能优势 - PostgreSQL/Oracle/SQL Server 支持该语法;MySQL 8.0+ 也支持,但 MySQL 5.7 不支持窗口函数
CUME_DIST 在什么场景下反而更合适
当你需要回答“某条记录在分组内的相对排名位置(含并列)”,比如:某产品销量在同类中处于前多少比例,而不是“到今天为止卖了总销量的百分之几”,这时 CUME_DIST 更准确、更简洁。
SELECT product, category, sales, ROUND(CUME_DIST() OVER (PARTITION BY category ORDER BY sales DESC) * 100, 2) AS dist_pct FROM products;
- 结果 95.0 表示“销量 ≥ 当前行的产品,占该分类全部产品的 95%”
- 如果误用
CUME_DIST替代移动累计,会出现:最后一条记录总是 100%,中间行跳跃不连续,且无法反映过程累积趋势 - 注意
CUME_DIST必须跟ORDER BY,且逻辑顺序直接影响结果(升序/降序决定“≤”还是“≥”的参照方向)
容易被忽略的类型与精度问题
计算百分比时,整数除法陷阱最常见:比如 SUM(col) / SUM(col) 在 PostgreSQL 或 SQL Server 中若字段为 INT,结果会截断为整数 0 或 1。
- 务必让分子或分母至少一方转为浮点,推荐写法:
SUM(col) * 100.0 / SUM(col)或CAST(SUM(col) AS DECIMAL(10,2)) - 使用
ROUND(..., 2)控制小数位,但注意:ROUND是四舍五入,不是截断;如需截断可用TRUNCATE(MySQL)或FLOOR(x*100)/100(通用) - 空值(
NULL)参与SUM自动忽略,但若整组全为NULL,分母为 0 会报错,建议加NULLIF:SUM(...) / NULLIF(SUM(...) OVER (...), 0)
移动累计百分比的关键不在函数名有多炫,而在窗口定义是否匹配业务时序逻辑——顺序错一位,结果就完全失真。











