CUME_DIST是累积分布函数,返回≤当前值的行数占分组总行数的比例(范围(0,1]),可用于识别尾部异常值,如通过CUME_DIST>0.95筛选前5%高值,且对重复值天然连续、比PERCENT_RANK更稳妥。

什么是 CUME_DIST,它真能识别异常值?
CUME_DIST 返回当前行在分组内的相对位置(0 到 1 之间),定义为「≤当前行值的行数 / 分组总行数」。它不直接标出异常值,但能帮你定位分布尾部——比如 CUME_DIST > 0.95 或 CUME_DIST PERCENT_RANK 不同。
怎么写才能避免常见错误?
最容易错的是漏掉 ORDER BY ——CUME_DIST() 必须配合窗口 ORDER BY,否则报错(如 PostgreSQL 报 window function requires an ORDER BY clause)。另外,别在 WHERE 中直接引用 CUME_DIST 别名,得用子查询或 CTE:
SELECT * FROM ( SELECT amount, CUME_DIST() OVER (ORDER BY amount) AS cume FROM sales ) t WHERE cume > 0.95 OR cume < 0.05;
- 不能写
WHERE CUME_DIST() OVER (...) > 0.95—— 窗口函数不能出现在WHERE - 如果按类别分组分析(如每类商品的销售异常),必须加
PARTITION BY category - NULL 值默认排在最前(ASC)或最后(DESC),会影响累积结果;需要统一处理,比如
ORDER BY COALESCE(amount, -999999)
CUME_DIST 和 PERCENT_RANK 选哪个?
两者都用于分布分析,但逻辑不同:CUME_DIST 是「≤当前值的比例」,最小值也返回 > 0 的值(如 2 行中最小值是 0.5);PERCENT_RANK 是「严格小于当前值的比例」,最小值固定为 0。想捕获“顶部 5% 包含并列最高值”时,CUME_DIST 更稳妥;想排除并列、只看严格排序位置,选 PERCENT_RANK。例如 5 条记录值全为 100:CUME_DIST 全是 1.0,PERCENT_RANK 全是 0.0。
实际查异常时要注意什么?
累积分布本身不判断异常,只是提供位置信号。真实场景中需结合业务理解阈值:
- 0.99 分位可能在日志延迟场景里是正常高峰,在财务报销里就是强异常
- 单靠
CUME_DIST无法区分「离群但合理」和「数据错误」,建议叠加标准差或 IQR 过滤 - 大数据量下,
ORDER BY窗口排序开销明显,若仅需头部/尾部少量样本,先LIMIT再算分布更高效 - 某些数据库(如 MySQL 8.0+)支持,但旧版 MySQL、SQLite 不支持,用前先
SELECT CUME_DIST() OVER ()测试是否报错
真正难的不是写出这个函数,而是确定「多少才算异常」——分布形状、业务容忍度、下游系统承受力,这些没法靠 SQL 自动推导。

















