rank() 会跳过重复名次是因为其设计逻辑为“相同值同排名,后续名次跳过已被占用位置”,如95,95,95,87→1,1,1,4;而dense_rank()则紧接排序→1,1,1,2。

为什么 RANK() 会跳过重复名次?
RANK() 的设计逻辑就是「相同值获得相同排名,后续名次跳过已占用位置」。比如三个人并列第1名(都是95分),RANK() 就会给下一名直接排第4,中间的2和3被跳过——这不是 bug,是标准行为。
常见错误现象:看到「第1、第1、第1、第4」这种结果就以为写错了,其实完全符合 SQL 标准定义。
使用场景:学校公示成绩时明确要求「同分同名,后位顺延」(即体现并列感),而非严格连续编号。
RANK() 和 DENSE_RANK() 的关键区别在哪?
两者都处理重复值,但跳位策略不同:
-
RANK():并列后跳过所有被占位次 →95,95,95,87→1,1,1,4 -
DENSE_RANK():并列后只跳1位 →95,95,95,87→1,1,1,2
性能上无差异,函数开销几乎一致;兼容性也很好,MySQL 8.0+、PostgreSQL、SQL Server、Oracle 都支持。
参数完全一样:RANK() OVER (ORDER BY score DESC),只是把 RANK 换成 DENSE_RANK 就能切逻辑。
怎么在实际查询中避免混淆名次类型?
别只写 RANK() 就完事,容易让后续维护的人误判语义。建议显式命名列,并加注释说明规则:
一款AI办公效率工具,主要用于适用于兼容 Agent Skills 产品的通用(非 OpenClaw)Nutrient DWS 文档处理技能。最佳搭配:Claude Code、Codex CLI、Gemini CLI、Cursor、Wi...,适合需要提升相关任务效率的用户。
SELECT student_id, score, RANK() OVER (ORDER BY score DESC) AS rank_with_gaps, -- 同分同名,后续跳位 DENSE_RANK() OVER (ORDER BY score DESC) AS rank_no_gaps -- 同分同名,后续紧接 FROM exam_results;
如果业务方说「要的是不跳的排名」,别硬调 RANK() 加逻辑绕,直接换 DENSE_RANK() 更安全。
注意:ORDER BY 中 NULL 默认排最前(ASC)或最后(DESC),若成绩字段可能为空,需提前用 COALESCE(score, 0) 或 WHERE score IS NOT NULL 明确过滤,否则 NULL 也会参与排名并影响跳位计算。
遇到 GROUP BY 后还要排名怎么办?
RANK() 是窗口函数,不能直接套在聚合结果上——比如先按班级 GROUP BY class 再排名,会报错「invalid use of aggregate function」。
正确做法是用子查询或 CTE 先算出明细排名,再聚合(如取每班前三):
WITH ranked AS (
SELECT
class,
student_id,
score,
RANK() OVER (PARTITION BY class ORDER BY score DESC) AS rnk
FROM exam_results
)
SELECT class, student_id, score
FROM ranked
WHERE rnk <p><code>PARTITION BY class</code> 是关键,它让排名在每个班级内独立重置,否则全校一起排就失去班级维度意义。</p><p>容易踩的坑:在 <code>GROUP BY</code> 查询里直接写 <code>RANK() OVER (...)</code>,MySQL 和 PostgreSQL 都会拒绝执行。</p><p>实际用的时候,最常被忽略的是 NULL 处理和 PARTITION BY 的必要性——不是所有“分组排名”都天然带分区,漏写 <code>PARTITION BY</code> 导致全校统排,结果对不上业务预期,查起来反而更费时间。</p>










