DENSE_RANK()更适合并列不跳号,因其遇相同排序值共享同一排名且后续名次连续(如95,95,92→1,1,2),而RANK()会跳号(→1,1,3),ROW_NUMBER()则强制唯一编号。

为什么 DENSE_RANK() 比 RANK() 更适合并列不跳号
当多个用户得分相同时,你希望它们共享同一排名(比如两个 95 分都排第 1),且后续名次紧接其后(下一个最高分是 92 分,就该是第 2 名),而不是跳号——这时 DENSE_RANK() 是唯一合理选择。RANK() 会跳号(两个第 1 名后直接第 3 名),ROW_NUMBER() 则完全不并列。关键区别在于:相同排序键下,DENSE_RANK() 返回相同值,且全局连续递增。
基本写法和 ORDER BY 的绑定逻辑
DENSE_RANK() 必须配合 OVER() 子句,且里面必须有 ORDER BY;它不接受 PARTITION BY 时就是全表排序,加了才分组内独立排名。常见错误是漏写 ORDER BY 或误把条件写进 WHERE 后再排序,导致逻辑错位。
示例(按 score 降序并列排名):
SELECT name, score, DENSE_RANK() OVER (ORDER BY score DESC) AS rank_num FROM students;
注意:ORDER BY score DESC 决定了“高分优先”,升序则用 ASC(默认);DESC 不加括号,不能写成 ORDER BY (score DESC)。
多字段排序时的并列判定规则
当用多个字段排序(如先按 score,再按 submit_time),DENSE_RANK() 是否并列只看「所有排序字段是否完全一致」。只要任一字段不同,就算不同行,哪怕 score 相同。
- 想让同分者绝对并列?只写
ORDER BY score DESC,别加第二字段 - 想同分时按提交时间早者优先,但依然同分并列?不行——加
submit_time就会拆开并列 - 真需要“同分并列 + 时间仅作展示不参与排序”?得用子查询或 CTE 先去重/聚合,再套
DENSE_RANK()
MySQL 8.0+ 和 PostgreSQL 的兼容性提醒
DENSE_RANK() 在 MySQL 8.0+、PostgreSQL 8.4+、SQL Server 2005+、Oracle 8i+ 都支持,但旧版 MySQL(5.7 及以前)不支持窗口函数,强行使用会报错 FUNCTION xxx.DENSE_RANK does not exist。此时不能靠变量模拟(易出错且不可靠),应升级 MySQL 或改用应用层排序。
另外,SQLite 直到 3.25.0(2018 年)才支持,老版本也会报错 no such function: DENSE_RANK。如果目标环境不确定,先查 SELECT sqlite_version(); 或 SELECT VERSION(); 确认版本。
真正容易被忽略的是:ORDER BY 中的字段必须存在于 SELECT 列表中吗?不是必须,但若引用了未 SELECT 的字段(尤其在 GROUP BY 场景下),某些数据库(如较老 PostgreSQL)可能报错或行为不一致——稳妥起见,保持一致更省事。

















