DENSE_RANK() 并列不跳级而 RANK() 跳级,因前者每组占1名次、后者按前组数累加名次;必须用 OVER(ORDER BY ...),可选 PARTITION BY 且顺序不可颠倒。

为什么 DENSE_RANK() 能解决并列不跳级,而 RANK() 不行
核心区别在「跳级逻辑」:当有并列时,RANK() 会把后续名次空出来(比如两个第1名后直接跳到第3名),而 DENSE_RANK() 紧接着排(两个第1名后是第2名)。这源于它们对「相同排序值组」的计数方式不同——DENSE_RANK() 每组只占1个名次位置,RANK() 则按「前面已出现多少组」累加。
典型错误是误用 RANK() 后发现排名断层,却没意识到问题出在函数选型上。只要需求明确要“并列不跳级”,就该无条件选 DENSE_RANK(),不用犹豫。
DENSE_RANK() 的基本写法和分区控制
它必须配合 ORDER BY 使用,且可选加 PARTITION BY 实现分组内独立排名。常见漏写的是 OVER 子句的括号结构,少一对括号就会报错 Window function requires an OVER clause。
-
DENSE_RANK() OVER (ORDER BY score DESC):全表按分数降序排,相同分数得同一排名 -
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC):每个部门内单独排,销售部的第1名和研发部的第1名互不影响 - 注意:
PARTITION BY必须写在ORDER BY前面,顺序反了会语法报错
和 ROW_NUMBER()、RANK() 混用时的陷阱
三者常被一起测试,但行为差异直接影响业务逻辑。比如统计“前3名员工”,用 ROW_NUMBER() 可能筛出3人,用 DENSE_RANK() 可能筛出5人(若第3名有3人并列)。
- 并列场景下,
ROW_NUMBER()强制唯一编号(即使值相同也连续赋1/2/3),RANK()和DENSE_RANK()才真正反映“名次”语义 - 如果后续要
WHERE drk 取前三名,用 <code>DENSE_RANK()更符合业务直觉;但若需严格取最多3条记录,就得换ROW_NUMBER() - 性能上三者几乎无差别,优化重点应在
ORDER BY字段是否有索引,而非函数本身
MySQL 8.0+ 和 PostgreSQL 的兼容性提醒
DENSE_RANK() 在 MySQL 8.0+、PostgreSQL 8.4+、SQL Server 2005+ 都原生支持,但低版本 MySQL(如 5.7)不支持窗口函数,强行使用会报错 FUNCTION xxx does not exist。
- 确认版本:MySQL 执行
SELECT VERSION();,PostgreSQL 执行SELECT version(); - 替代方案(仅限无窗口函数环境):用自连接或变量模拟,但逻辑复杂、易出错、无法高效处理大数据量
- 别信“加个 GROUP BY 就能替代”的说法——
GROUP BY无法保留原始行粒度,根本没法实现每行带排名
真正麻烦的不是语法怎么写,而是没确认执行环境是否支持。写完测试前,先看一眼数据库版本。

















