RANK()和DENSE_RANK()必须配合OVER(ORDER BY ...)使用,漏ORDER BY会报错;RANK()并列跳名次(1,1,3),DENSE_RANK()不跳(1,1,2);二者均需注意ORDER BY稳定性、返回类型为BIGINT,且不可替代ROW_NUMBER()用于分页。

RANK() 和 DENSE_RANK() 必须配合 OVER 使用
不写 OVER 就会报错,比如 RANK() 单独出现是语法错误;OVER 里至少得有 ORDER BY,否则数据库不知道按什么排。漏掉 PARTITION BY 不会报错,但结果是全表统一编号,不是你想要的“每组内排名”。常见错误现象:查出来所有行的排名都是 1,大概率是 ORDER BY 后面字段值全一样,或者字段本身为 NULL 且没加 NULLS LAST。
并列时跳名次 vs 不跳名次:RANK() 返回 1,1,3;DENSE_RANK() 返回 1,1,2
这是两者最直接的区别,影响后续逻辑判断。比如你要取“每组前 3 名”,用 RANK() 可能只返回 2 行(两个并列第 1,一个第 3),而 DENSE_RANK() 在同样数据下会返回 4 行(1,1,2,3)。反过来,如果你依赖“第 2 名”一定存在,用 RANK() 就可能查不到——因为被跳过了。实际业务中:DENSE_RANK() 更适合做分档(如 Top 3 客户档位),RANK() 更适合强调层级断层(如“淘汰掉前两名之后的全部人”,这时跳过的名次本身就是信号)。
在存储过程中嵌套使用时要注意 ORDER BY 稳定性
如果 ORDER BY 字段有重复值,又没加唯一键兜底(比如 ORDER BY score DESC, id ASC),不同执行批次结果可能不一致。尤其在 SQL Server 或 MySQL 8.0+ 的存储过程中,优化器可能重排执行顺序,导致排名波动。建议始终在 ORDER BY 中加入一个确定性字段,例如主键或时间戳。另外:RANK() 和 DENSE_RANK() 都返回 BIGINT 类型,在定义临时表字段或输出参数时别用 INT,否则超限时会截断。
别把 RANK() 当分页工具用
ROW_NUMBER() 才是分页的正确选择;RANK() 和 DENSE_RANK() 在遇到并列时会返回相同数字,导致 WHERE rank = 2 可能命中多行甚至零行。比如查“第二高工资”,用 RANK() 在两人并列第一时就查不到第二名;用 DENSE_RANK() 虽然能查到,但若三人并列第一,它返回的“第二名”其实是第四高工资的人——因为前三名都被占了档位。真正要取第二高值,应该先 SELECT DISTINCT 再排序,而不是依赖排名函数。

















