PERCENT_RANK()按(r-1)/(n-1)计算,返回[0.0, 1.0]内值:首行恒为0.0,末行(n>1时)恒为1.0,并列值共享相同结果,单行返回NULL,且必须配合OVER子句使用。
PERCENT_RANK函数的计算逻辑和返回值范围
不是简单地把行号除以总行数,而是按公式
计算,其中
是该行在窗口内的
值(即并列时取相同名次,后续跳号)。这意味着:第一行永远是
,最后一行永远是
,中间值严格落在
区间内(注意不是闭区间)。
常见误解是以为它等价于
,但后者会把最后一名算成
,且不处理并列——实际结果偏差明显。
使用场景包括:用户成绩分档、销售员业绩分布分析、指标在群体中的相对位置评估。
必须配合WINDOW子句使用,不能单独写在SELECT列表里
是一个窗口函数,没有
子句会直接报错:
。它不能像普通聚合函数那样用在
后,也不能在
或
中直接引用(因为窗口计算发生在这些子句之后)。
实操建议:
先写好
部分,比如按销售额降序排:
如需分区计算(比如每部门独立排名),加
,注意此时每个分区内首尾仍为
和
避免在子查询外层直接
—— 应该用 CTE 或嵌套查询先算出百分位,再过滤
和RANK、DENSE_RANK、CUME_DIST的区别在哪
容易混淆的是这几个排名函数的语义差异:
:并列时占位(如 1,1,3),
基于此计算,所以并列项得到相同百分比值
:并列不占位(如 1,1,2),但
不基于它,不能混用
:计算“≤当前值的行数占比”,结果范围是
,首行可能大于
,末行恒为
:强行分桶,不是连续比例,会有大量重复值,也不反映真实累积分布
举例:4 行数据排序后值为 [10,20,20,30],
返回
;而
返回
。
NULL值怎么处理?ORDER BY里的NULLS FIRST/LAST会影响结果
本身不单独处理
,它的行为完全由
子句决定。默认情况下,
被视为最大值(即排在最后),所以如果字段含
且未显式声明顺序,它们会集中在末尾,导致
出现多个
(只要
行不是唯一末尾行)。
实操建议:
明确写
或
,避免依赖默认行为
若业务要求忽略
行,先用
过滤,否则
行参与计数和排序,会拉低其他行的百分比
测试时故意插入几条
数据,观察返回值是否符合预期,这是最容易被忽略的验证点
实际应用中,最常出问题的是把
当作“前10%”筛选工具直接用,却没意识到它对
敏感、不能在
里直用、且并列逻辑和业务理解不一致——这些细节不提前确认,跑出来的报表可能全盘偏移。
PERCENT_RANK()(rank - 1) / (total_rows - 1)rankRANK()0.01.0[0, 1)ROW_NUMBER() OVER (...)::float / COUNT(*) OVER ()1.0PERCENT_RANK()OVERERROR: window function PERCENT_RANK requires a window specificationGROUP BYWHEREHAVINGORDER BYPERCENT_RANK() OVER (ORDER BY sales DESC)PARTITION BY dept_id0.01.0WHERE percentile > 0.9RANK()PERCENT_RANK()DENSE_RANK()PERCENT_RANK()CUME_DIST()(0, 1]0.01.0NTILE(100)PERCENT_RANK()[0.0, 0.333, 0.333, 1.0]CUME_DIST()[0.25, 0.75, 0.75, 1.0]PERCENT_RANK()NULLORDER BYNULLNULLPERCENT_RANK()1.0NULLORDER BY score DESC NULLS LASTNULLS FIRSTNULLWHERE score IS NOT NULLNULLNULLPERCENT_RANK()NULLWHERE