row_number()为每行分配唯一连续序号,相同值也不同号;rank()对相同值分配同名次并跳过后续编号,导致排名不连续。

ROW_NUMBER() 和 RANK() 的核心区别就一条:遇到相同排序值时,前者强制给不同序号,后者给相同排名并跳过后续编号。
ROW_NUMBER():每行一个唯一编号,不管值是否重复
它不关心数据是否并列,只按 ORDER BY 指定的顺序从 1 开始挨个编号。哪怕两行 salary 都是 8000,也会得到 2 和 3 这样的连续但不“公平”的序号。
常见错误现象:
想取“每个部门薪资最高的员工”,却用 ROW_NUMBER() + PARTITION BY dept_id ORDER BY salary DESC,结果同薪员工里只随机留一个——这不是 bug,是它本来的设计。
适用场景:
• 分页(必须保证序号连续且唯一)
• 去重(如保留每个 user_id 最新一条记录)
• 生成临时行号用于后续逻辑处理
RANK():并列就同名次,下一个名次直接跳号
当多行排序字段值相等时,RANK() 给它们分配完全相同的排名;紧接着的下一名,序号会跳过被并列占用的位置。比如两个第 2 名之后,下一个是第 4 名,没有第 3 名。
典型错误写法:
误以为 RANK() 返回的是“密集”序号,结果在做 Top 5 排行榜时漏掉实际第 3 名的人(因为第 3 名被跳过了)。
使用注意:
• RANK() 的结果可能不连续(含空缺)
• 如果业务要求“前 N 名”且允许并列,需用 WHERE rank_num ,不能用 <code>rank_num IN (1,2,3,4,5) —— 后者会漏掉第 5 名之后因跳号而实际存在的第 5 名
DENSE_RANK():并列也同名次,但下一个名次紧挨着
它和 RANK() 一样处理并列,但不跳号。两个第 2 名之后,下一个是第 3 名。这是真正“无间隙”的名次序列。
为什么常被忽略:
很多人默认用 RANK(),直到发现排行榜出现“1、2、2、4、5”这种断层才意识到要换。其实只要业务上需要“第 N 名就是物理上第 N 个位置”,就应该优先考虑 DENSE_RANK()。
参数差异:
三者语法完全一致:FUNCTION() OVER (PARTITION BY ... ORDER BY ...),区别只在函数名本身。别试图靠改 ORDER BY 或加 PARTITION BY 让 RANK() 变成密集排名——做不到。
真正容易踩的坑不在语法,而在对“名次”含义的理解:数据库不会替你判断业务规则。同一个排序字段,ROW_NUMBER() 是流水号,RANK() 是奥运奖牌榜(双银牌后直接铜牌),DENSE_RANK() 是考试成绩单(90 分并列第 2,下一个 85 分就是第 3)。选错函数,结果可能合法,但业务上完全错位。










