0Pricing
Coding Interview Prep · 课时

处理前 N 名中的并列值

了解何时使用 RANK 或 DENSE_RANK,以便包含所有并列行

处理前 N 名中的并列值 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。

并列追问

当您用 ROW_NUMBER 完成每组前 N 名的问题后,面试官可能会继续追问:“如果截止位置上有两名员工的薪资完全相同,是否应该将两人都包括在内?”

这能区分出只是记住了一个查询的候选人,以及真正理解排名语义的候选人。答案取决于在 ROW_NUMBER、RANK 和 DENSE_RANK 之间进行选择。本课将说明每个函数分别对应什么业务意图。

ROW_NUMBER 会隐藏并列

ROW_NUMBER 会为每一行分配严格唯一的整数。即使两行在排序列上并列,其中一行也会获得 2,另一行获得 3,顺序可能是任意的。

结果是:WHERE rn <= 3 筛选条件会返回恰好 3 行,并且可能悄悄排除本应被包括的并列行。如果您确实需要固定数量的行,这没有问题;但如果所有并列行都应符合条件,这样做就是错误的。

-- Salaries: 100, 90, 90, 80
-- ROW_NUMBER -> 1, 2, 3, 4  (the two 90s get 2 and 3 arbitrarily)
ROW_NUMBER() OVER (ORDER BY salary DESC)

RANK 会留下间隔

RANK 会为并列行分配相同的排名,然后为计入并列而跳过后续排名。两行并列第 2 名时,它们都是 2,下一行会直接跳到第 4 名,而不是第 3 名。

当您需要“前 3 个名次”,且一个名次可以由多人占据时,请使用 RANK。这类似于真实的竞赛排名:两名银牌得主意味着没有铜牌得主。

-- Salaries: 100, 90, 90, 80
-- RANK -> 1, 2, 2, 4   (rank 3 is skipped)
RANK() OVER (ORDER BY salary DESC)

DENSE_RANK 不会留下间隔

DENSE_RANK 同样会为并列行分配相同的排名,但之后不会跳过排名。两行并列第 2 名时,它们都是 2,接下来的不同值排名为 3。

当问题关注的是不同值时,请使用 DENSE_RANK,例如“薪资最高的 3 个不同等级”或“前 3 个价格层级”。它统计的是唯一值,而不是行数。

-- Salaries: 100, 90, 90, 80
-- DENSE_RANK -> 1, 2, 2, 3   (no gap)
DENSE_RANK() OVER (ORDER BY salary DESC)

并列对比

对于薪资列表 100、90、90、80,三个函数的结果如下:

  • ROW_NUMBER:1、2、3、4
  • RANK:1、2、2、4
  • DENSE_RANK:1、2、2、3

这张表值得熟练记忆。面试官可能会直接要求您为给定列表填表,而正确掌握是否存在间隔正是考察重点。

SELECT salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn,
  RANK()       OVER (ORDER BY salary DESC) AS rnk,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees;

使用 RANK 包括所有并列行

如果要回答“前 3 名,但包括截止位置上所有并列者”,请筛选 RANK() <= 3。如果两人并列第 3 名,两人都会出现,因此结果可能包含超过 3 行。

这正是“前 3 个名次”而不是“任意 3 行”这类问法背后的意图。请明确说明,出现并列时行数可能超过 N。

WITH ranked AS (
  SELECT name, department, salary,
         RANK() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
SELECT name, department, salary, rnk
FROM ranked
WHERE rnk <= 3
ORDER BY department, rnk;

使用 DENSE_RANK 获取前 3 个不同等级

当需求是“薪资最高的 3 个不同等级”,并且希望包括处于这三个等级的每一名员工时,请使用 DENSE_RANK() <= 3。

这可能返回很多行:前三个薪资等级中的所有员工,无论这些等级中有多少人。关键在于,DENSE_RANK 统计的是不同值,因此筛选条件选出的是值的层级,而不是固定数量的行。

WITH ranked AS (
  SELECT name, salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
  FROM employees
)
SELECT name, salary, drnk
FROM ranked
WHERE drnk <= 3
ORDER BY drnk;

选择指南

根据题目措辞选择函数:

  • “恰好 N 行”或分页 → ROW_NUMBER(添加并列处理键)。
  • “前 N 个名次,并列者共享名次” → RANK。
  • “前 N 个不同值/等级/层级” → DENSE_RANK。

如果需求不明确,请询问:“如果截止位置出现并列,我应该包括所有并列行,还是将结果限制为 N 行?”提出这个澄清问题本身就能获得认可。

并列处理键仍然重要

即使使用 RANK 或 DENSE_RANK,添加次要的 ORDER BY 键也能控制并列行的显示顺序,并使输出保持稳定。它不会改变哪些行符合条件,但会让结果可复现。

使用 ROW_NUMBER 时,并列处理键至关重要,因为它会决定哪一行能够通过 rn 截止条件。

RANK() OVER (
  PARTITION BY department
  ORDER BY salary DESC, name ASC
) AS rnk

完整示例:得分最高者

一个 game_scores 表包含 player 和 score。面试官想要“得分排名前 2 的名次中的所有选手”。如果第一名出现并列,就会有两名选手并列第 1 名,接下来的不同得分为第 2 名。

“名次”且并列后不跳号,说明应使用 DENSE_RANK。如果面试官说的是“前 2 个有间隔的排名”,您就应改用 RANK。请仔细听清确切措辞。

WITH r AS (
  SELECT player, score,
         DENSE_RANK() OVER (ORDER BY score DESC) AS pos
  FROM game_scores
)
SELECT player, score, pos
FROM r
WHERE pos <= 2
ORDER BY pos, player;

需要避免的常见错误

面试官会留意以下陷阱:

  • 当题目要求包括并列行时使用 ROW_NUMBER,导致符合条件的行被悄悄排除。
  • 混淆 RANK 和 DENSE_RANK 是否会产生间隔。
  • 忘记 RANK/DENSE_RANK 筛选可能返回超过 N 行,然后错误地声称结果有问题。
  • 当问题要求每组前 N 名时遗漏 PARTITION BY,结果变成对整张表排名。

快速检查

请根据所描述的并列处理方式选择正确的排名函数。

回顾:并列处理

三个函数,三种并列处理方式:

  • ROW_NUMBER:始终唯一,恰好返回 N 行,并列时任意打破平局。
  • RANK:并列项共享排名,随后会出现排名间隔。
  • 密集排名:并列项共享排名,不产生间隔,按不同值计数。

请根据问题的措辞进行选择;含义不明确时请提出澄清问题,并记住,RANK/DENSE_RANK筛选结果按设计可能多于 N 行。

常见问题解答

「处理前 N 名中的并列值」课时是免费的吗?

是的 — 「处理前 N 名中的并列值」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。

「处理前 N 名中的并列值」这节课中我会学到什么?

了解何时使用 RANK 或 DENSE_RANK,以便包含所有并列行 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Coding Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「处理前 N 名中的并列值」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Coding Interview Prep 课中编写并运行代码吗?

能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 ROW_NUMBER 获取各组前 N 行
  2. 处理前 N 名中的并列值
  3. 安全地去除重复行
  4. 保留每个键对应的最新行
← 返回 Coding Interview Prep