导读:本期聚焦于小伙伴创作的《SQL窗口函数中RANK和ROW_NUMBER到底有什么区别?面试常考用法解析》,敬请观看详情。面试时被问到如何给部门员工按工资排名,不少人随手写出ROW_NUMBER,却忽略并列名次的场景。RANK与ROW_NUMBER虽同属窗口函数,但处理相同值的方式完全不同。RANK遇到并列会跳过后续序号,ROW_NUMBER则强制赋予唯一连续整数。理解二者差异,要抓住OVER子句中PARTITION BY与ORDER BY的配合逻辑。本文通过具体查询示例,说明在统计销售业绩、剔除重复数据等题目中的正确选型,帮你避开只写函数名却说不清语义的失分点。

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

SQL窗口函数中RANK和ROW_NUMBER到底有什么区别?面试常考用法解析

一、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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。