在SQL面试里,窗口函数几乎是必考内容,而RANK和ROW_NUMBER这两个排序函数经常成对出现。它们都能在保留原表行的同时算出序号,但语义差别直接影响查询结果,用错就会导致业务逻辑偏差。许多题目表面要求排名,实际暗含是否允许并列的考点,候选人若只背语法而不理解行为差异,很容易在白板题上写出错误SQL。

一、RANK与ROW_NUMBER的基础定义
窗口函数由函数名加OVER子句组成,OVER里通过PARTITION BY划分分组,ORDER BY决定组内排序规则。RANK属于跳跃排序函数:当有多行ORDER BY值相同时,它们会拿到相同排名,紧接着的排名会按行数跳过。ROW_NUMBER则最简单粗暴,每一行都被赋予一个不重复、从1开始的连续整数,即使值相同也强制区分先后。
从底层看,ROW_NUMBER在排序后仅做行号累加,不感知值是否相等;RANK则需要比较相邻行的排序键,发现相等就共享序号,并维护一个计数器记录已消耗的名次。因此同样的数据集,两者输出列往往不同。下面用一张员工表直观对比。
-- 员工表 emp: dept_id, emp_name, salary CREATE TABLE emp ( dept_id INT, emp_name VARCHAR(20), salary INT ); INSERT INTO emp VALUES (1, '张三', 5000), (1, '李四', 5000), (1, '王五', 4000), (2, '赵六', 6000), (2, '钱七', 5500);
二、同数据下的结果差异示例
我们对部门1的员工按工资降序排列,分别使用两个函数。可以清楚看到,张三和李四工资相同,RANK给两人都标为1,王五因为第三高变成3;ROW_NUMBER不管并列,直接给1、2、3。
SELECT emp_name, salary, RANK() OVER (ORDER BY salary DESC) AS rk, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn FROM emp WHERE dept_id = 1; -- 结果: -- 张三 5000 rk=1 rn=1 -- 李四 5000 rk=1 rn=2 -- 王五 4000 rk=3 rn=3
这个例子暴露了面试常见陷阱:如果题目说“取每个部门工资最高的两人”,用RANK可能返回三人(并列第一算两人再加第二),而ROW_NUMBER严格取前两行。候选人必须根据业务含义选函数,并向面试官说明取舍。
三、PARTITION BY结合时的面试套路
真实面试题通常不会只排全局,而是“每个部门内排名”。此时在OVER中加PARTITION BY dept_id,两个函数都会在部门内重新从1开始计序。下面查询列出各部门薪水名次。
SELECT dept_id, emp_name, salary, RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dept_rk, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dept_rn FROM emp;
部门2中,赵六6000得1,钱七5500得2,两个函数结果一致,因为没有并列。但在部门1依然出现RANK并列、ROW_NUMBER不并列。面试官常追加问题:如何只保留每个部门工资最高的且去重?这时用ROW_NUMBER=1即可稳定取一行,用RANK=1可能多出并行,需要再辅以其他条件。
另一个考点是性能:ROW_NUMBER因不需比较同级,数据库优化器有时能更早起序,但在多数现代引擎中二者成本接近。回答时强调语义而非盲目说谁快,显得更专业。
四、典型面试题与作答思路
题目常写为“找出每个部门工资第二高的员工”。若用RANK,当存在两个并列第一时,RANK=2可能为空,导致漏人;稳妥写法是用ROW_NUMBER取rn=2,或结合DENSE_RANK理解间隙。以下给出ROW_NUMBER解法:
SELECT dept_id, emp_name, salary
FROM (
SELECT
dept_id,
emp_name,
salary,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM emp
) t
WHERE rn = 2;
若题目明确“允许并列,第二档成绩含并列”,则应改用DENSE_RANK,但既然考RANK和ROW_NUMBER,核心还是讲清为什么ROW_NUMBER能精确取第N行。回答时建议口述:ROW_NUMBER保证唯一性,适合分页与去重;RANK表达竞赛排名,适合奖牌分配场景。
最后提醒,窗口函数执行顺序在WHERE和GROUP BY之后,所以子查询包装是常见的。面试写题时顺手补上括号别名,能减少语法扣分。掌握这些细节,RANK与ROW_NUMBER的题基本能拿稳。
SQL窗口函数RANKROW_NUMBER修改时间:2026-08-06 18:18:41