数据库系统工程师 · 高频练习

每个部门取工资最高的 2 名员工,为什么要用 PARTITION BY?

中级 单选题 第 909 题 中等 数据库系统工程师SQLROW_NUMBER窗口函数分组Top N
题目

要从 employee(dept_id, emp_id, salary) 中查询每个部门工资最高的 2 名员工。下列核心思路正确的是()。

A 仅按 dept_id 做 GROUP BY,并直接选择任意 emp_id
B 全表按 salary 降序后只取前 2 行
C 使用 ROW_NUMBER() OVER(PARTITION BY dept_id ORDER BY salary DESC),再筛选序号不大于 2
D 把 salary 转成字符串后按字典序取前 2 行
题目类型:原创高频练习题 用途:用于帮助理解数据库系统工程师相关考点和答案解析,不等同于官方真题。
正确答案
C
答案解析

PARTITION BY dept_id 会让窗口序号在每个部门内重新从 1 开始,ORDER BY salary DESC 决定部门内排名。外层筛选 rn<=2,才能得到每个部门各自的前 2 名。

选项分析

A

错误。普通 GROUP BY 不能在不聚合的情况下稳定返回对应员工明细。

B

错误。它只返回全表工资最高的两行,不是每个部门两行。

C

正确。按部门分区、按工资降序编号,再筛选每组前两行。

D

错误。字符串排序会让数值大小关系失真,也没有解决分组排名。

本题为什么容易错

“分组”两个字很容易让人条件反射地选 GROUP BY。但本题不是只求每组最大值,还要保留前两名员工的整行信息,这正是窗口函数更顺手的地方。

先看结论

简短答案

每个部门取工资最高的 2 名员工,为什么要用 PARTITION BY,正确答案是 C(使用 ROW_NUMBER() OVER(PARTITION BY dept_id ORDER BY salary DESC),再筛选序号不大于 2)。PARTITION BY dept_id 会让窗口序号在每个部门内重新从 1 开始,ORDER BY salary DESC 决定部门内排名。外层筛选 rn<=2,才能得到每个部门各自的前 2 名。

解析

易混淆概念对比表

概念本题判断区别要点记忆提示
仅按 dept_id 做 GROUP BY,并直接选择任意 emp_id 本题干扰项 错误。普通 GROUP BY 不能在不聚合的情况下稳定返回对应员工明细。 看到该词不要急着选,先判断是否真正解决题干问题
全表按 salary 降序后只取前 2 行 本题干扰项 错误。它只返回全表工资最高的两行,不是每个部门两行。 看到该词不要急着选,先判断是否真正解决题干问题
使用 ROW_NUMBER() OVER(PARTITION BY dept_id ORDER BY salary DESC),再筛选序号不大于 2 本题正确答案 正确。按部门分区、按工资降序编号,再筛选每组前两行。 看到题干核心场景时优先联想到它
把 salary 转成字符串后按字典序取前 2 行 本题干扰项 错误。字符串排序会让数值大小关系失真,也没有解决分组排名。 看到该词不要急着选,先判断是否真正解决题干问题
本题易混淆选项怎么区分
  • 仅按 dept_id 做 GROUP BY,并直接选择任意 emp_id:错误。普通 GROUP BY 不能在不聚合的情况下稳定返回对应员工明细。
  • 全表按 salary 降序后只取前 2 行:错误。它只返回全表工资最高的两行,不是每个部门两行。
  • 把 salary 转成字符串后按字典序取前 2 行:错误。字符串排序会让数值大小关系失真,也没有解决分组排名。
复习

知识点详解

窗口函数在不折叠明细行的前提下计算排名、累计值和前后行信息。ROW_NUMBER 对每行给出唯一连续序号;RANK 遇到并列会跳号;DENSE_RANK 并列但不跳号。分组 Top N 的业务定义若不明确,并列边界可能直接改变返回行数。数据量较大时,还要结合分区列和排序列设计索引并查看执行计划。

备考速记

每组重排靠 PARTITION BY,组内先后靠 ORDER BY。

SQL 在分组Top N场景中的作用

SQL在本题中的核心价值,是解决“要从 employee(dept_id, emp_id, salary) 中查询每个部门工资最高的 2 名员工。下列核心思路正确的是()”这个场景问题。复习时不要只背选项名称,还要理解它为什么适用于该场景,以及它能解决哪类安全、流程或管理问题。

拓展

同类题怎么考

  • 每个班级、部门或商品类别取前 N 条记录。
  • 比较 ROW_NUMBER、RANK 与 DENSE_RANK 的并列处理。
SQL 在数据库系统工程师软考中的考法

软考选择题通常不会只考概念定义,还会把SQL放到分组Top N场景中,要求判断它的作用、适用范围或与相近概念的区别。遇到这类题时,先抓住题干中的业务场景,再看哪个选项最能解决该场景下的核心问题。

解题思路

先问清楚“前 2 名”是在全公司排,还是每个部门各排一次。选项 B 只会给出全公司两个人;PARTITION BY 才像把员工按部门分到不同教室,每个教室重新编号。ROW_NUMBER 得到序号后还要套一层查询筛 rn<=2,因为多数数据库不能在同一层 WHERE 里直接使用刚算出的窗口别名。

考点定位

GROUP BY 会把多行聚合成组结果,窗口函数保留明细行并在组内计算序号。题干既要员工明细又要每组排名时,优先考虑窗口函数。

易错提醒

  • 漏写 PARTITION BY,结果变成全表统一排名。
  • 工资并列时没有考虑 ROW_NUMBER、RANK、DENSE_RANK 的差异。
  • 直接在同层 WHERE 使用窗口函数别名,忽略 SQL 执行阶段。

备考提示

  • 先确认并列工资要固定两行,还是要把并列名次全部保留,再选择排名函数。
  • 生产查询再补稳定排序字段,例如 `salary DESC, emp_id`,避免同薪顺序漂移。

你可能还想了解

  • ROW_NUMBER 和 RANK 有什么区别?
  • 窗口函数为什么不能直接写在 WHERE?
  • GROUP BY 和 PARTITION BY 有什么区别?

本文小结

每个部门都要重新排名,因此用PARTITION BY dept_id划分窗口,并按salary降序生成ROW_NUMBER;外层筛选rn<=2即可保留每个部门的两条员工明细。