percent_rank是窗口函数,返回0到1间的相对排名,公式为(rank-1)/(total_rows-1);rank和dense_rank返回整数名次,不归一化,且处理并列方式不同:rank跳号,dense_rank连续,而percent_rank对相同值赋予相同百分比排名。

PERCENT_RANK 是什么,它和 RANK、DENSE_RANK 有什么区别?
PERCENT_RANK 是窗口函数,返回当前行在分组内的相对排名(0 到 1 之间),计算公式是 (rank - 1) / (total_rows - 1)。注意:它不是「第多少百分位」的值(比如 P95),而是「排在前百分之几的位置」。
-
RANK()和DENSE_RANK()返回整数排名,不归一化; -
PERCENT_RANK()总是让首行 = 0,末行 = 1(只要分组行数 ≥ 2); - 如果分组只有 1 行,
PERCENT_RANK()返回 0(因为分母为 0,SQL 标准定义为 0)。
怎么写一个基础的 PERCENT_RANK 查询?
必须搭配 OVER() 子句,且至少指定 ORDER BY;PARTITION BY 可选(用于分组内独立计算)。
SELECT name, score, PERCENT_RANK() OVER (ORDER BY score) AS pct_rank FROM students;
-
ORDER BY score决定升序排名(分数越低,PERCENT_RANK越小); - 若想「高分排前面」,改用
ORDER BY score DESC; - 不加
PARTITION BY就是对全表统一排序计算; - 多个相同
score值会得到相同PERCENT_RANK(因为 rank 相同,公式结果就相同)。
常见错误:为什么结果里全是 0 或 NaN?
- 出现全 0:很可能
OVER() 里漏了 ORDER BY —— 某些数据库(如 PostgreSQL)允许无 ORDER BY,但此时所有行视为同 rank,导致 (1-1)/(n-1)=0;
- 出现
NULL:当 score 字段本身为 NULL,且数据库按默认规则把 NULL 排在最前或最后(不同 DB 行为不同),可能干扰 rank 计算;建议显式控制:ORDER BY score DESC NULLS LAST;
- 分组只有 1 行时,
PERCENT_RANK 固定为 0 —— 这不是 bug,是标准定义,别误以为计算失效;
- 在 MySQL 8.0 之前不支持窗口函数,会报错
ERROR 1064,确认版本:SELECT VERSION();。
和 PERCENTILE_CONT 的关键区别在哪?
OVER() 里漏了 ORDER BY —— 某些数据库(如 PostgreSQL)允许无 ORDER BY,但此时所有行视为同 rank,导致 (1-1)/(n-1)=0;NULL:当 score 字段本身为 NULL,且数据库按默认规则把 NULL 排在最前或最后(不同 DB 行为不同),可能干扰 rank 计算;建议显式控制:ORDER BY score DESC NULLS LAST;PERCENT_RANK 固定为 0 —— 这不是 bug,是标准定义,别误以为计算失效;ERROR 1064,确认版本:SELECT VERSION();。PERCENT_RANK 是「你排第几百分位」,而 PERCENTILE_CONT 是「第 X 百分位对应的值是多少」——二者目的完全相反。
- 想知道「张三的销售额在团队中处于前 12%」→ 用
PERCENT_RANK(); - 想知道「团队销售前 10% 的门槛是多少(即 P90 值)」→ 用
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY sales); -
PERCENT_RANK必须作为窗口函数使用,不能出现在聚合上下文(比如GROUP BY后直接用它); - 它不接受参数,不像
PERCENTILE_CONT那样要传入 0.5、0.9 等。
实际用的时候,最容易混淆的是把 PERCENT_RANK 当成「求百分位数值」的工具。它只回答位置,不回答阈值。











