CUME_DIST 这个函数,算的是当前行在分区里“小于等于它的值的行数占比”,结果范围在 (0,1] 之间。它是基于实际行数算累积分布,相同值返回相同结果,必须配合 ORDER BY 用,也能加上 PARTITION BY 做分组。

什么是 CUME_DIST,它返回什么值?
说白了,CUME_DIST 就是一个窗口函数,帮你算当前行在分区里“比它小的或相等的行数,占整个分区的比例”。它不按排名编序号,而是直接甩给你一个累积分布比例——最小值起码是 1/总行数,最大值永远等于 1.0。
这里有个关键点:它看的是值的大小,不是排名位置。换句话说,如果两行销售额一样,它们拿到的累积概率就一模一样,结果严格落在 (0,1] 这个区间里。
怎么写基础语法才能正确算出销售额累积概率?
必须带上 ORDER BY 子句,而且 OVER() 不能省,否则数据库会报错 Window function requires an OVER clause。很多新手栽在只写 OVER(ORDER BY sales) 却忘了括号或者漏掉排序字段上。
SELECT product, sales, CUME_DIST() OVER (ORDER BY sales) AS cum_prob FROM orders;- 如果想按地区看各自的销售额分布,加上
PARTITION BY region - 注意:
ORDER BY里不能用别名,必须写原始列名或表达式。比如ORDER BY ABS(sales)没问题,但ORDER BY s(就算前面写了sales AS s)会直接报错。
为什么和 PERCENT_RANK 结果不一样?
这两个函数都算累积比例,但算法不同。CUME_DIST 是“小于等于当前值的行数 ÷ 总行数”;PERCENT_RANK 是“(排名 − 1)÷(总行数 − 1)”。一旦有重复值,区别就来了——前者对相同值返回相同结果,后者因为并行排名处理方式不同,结果会有差异。
举个例子:5 行数据里,3 行销售额都是 1000,那这 3 行的 CUME_DIST 都是 3/5 = 0.6;而 PERCENT_RANK 假设它们并列排第 2 名,所以都返回 (2−1)/(5−1) = 0.25。
实际分析销售额分布时容易忽略的细节
空值(NULL)默认排在最前面,这会影响累积概率的起点。如果销售额字段里有 NULL,CUME_DIST 会把它们全算进“≤ 当前行值”里,导致第一个非空值的结果被拉高。
- 建议预处理:用
WHERE sales IS NOT NULL过滤,或者用ORDER BY sales NULLS LAST(PostgreSQL/Oracle 支持这个写法,MySQL 8.0+ 不支持) - 主流数据库(MySQL 8.0+、PostgreSQL、SQL Server、Oracle)都支持
CUME_DIST,但 SQLite 不支持。 - 性能方面,如果
ORDER BY列没建索引,大表上跑窗口函数还是会触发全扫描排序,这个坑得提前踩好。
真正影响业务判断的,是你是否理解这个比例表示的是“相对于整个窗口的累计覆盖度”,而不是某个分位点的精确估计。别把两者搞混了。
