不存在第 N 个值时返回 NULL
掌握面试官喜欢考查的极端情况:优雅地处理行数不足
不存在第 N 个值时返回 NULL 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
面试官喜欢追问的边界情况
在您解决第 N 高值查询后,面试官又会问:“如果表中的不同薪资少于 N 个怎么办?我希望得到单个 NULL,而不是空结果。”
这个问题可以区分出只是记住查询语句的候选人和真正理解结果集行为的候选人。许多解决方案会悄悄返回零行,而不是返回包含 NULL 的一行。
本课的重点,就是强制返回恰好一行输出;当不存在第 N 个值时,该行的值为 NULL。
为什么单独使用 DENSE_RANK 不返回任何行
请回忆标准的第 N 高值查询。如果只有两个不同的薪资,而您要求第 3 高值,WHERE rnk = 3 就不会匹配任何内容,因此查询会返回一个空集:零行。
空集不同于包含 NULL 的一行。如果规范要求“返回 NULL”,那么即使底层逻辑正确,空结果也无法通过测试。
SELECT salary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employee
) t
WHERE rnk = 3; -- returns NO rows if fewer than 3 distinct salaries修复方法 1:包裹在外层 SELECT 中
最简单可靠的修复方法是:将整个第 N 高值查询作为标量子查询放入一个单独的 SELECT 中。没有匹配行的标量子查询会计算为 NULL,而外层 SELECT 始终会恰好生成一行。
这是 LeetCode 风格的“返回 NULL”变体的标准答案,并且适用于所有数据库方言。
SELECT (
SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 2 -- N = 3
) AS third_highest;标量子查询技巧为何有效
以下两条规则结合起来,就能得到您需要的行为:
- 标量子查询最多只能返回一个值。如果它不返回任何行,系统会将其替换为
NULL。 - 不带
FROM的外层 SELECT(或使用单行数据源)始终会输出恰好一行。
因此,内部查询找到第 N 个值时,您会得到该值;什么也找不到时,您会得到一行,其中包含 NULL。这正是面试官所要求的约定。
使用 DENSE_RANK 的修复方法 1
同样的包裹方法也适用于窗口函数解决方案。将排名查询放入标量子查询中;如果没有任何行的排名为 N,子查询就会产生 NULL,而外层 SELECT 仍会返回一行。
SELECT (
SELECT salary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employee
) t
WHERE rnk = 3
) AS third_highest;修复方法 2:MAX 会自动返回 NULL
请回忆第 1 课中的 MAX 嵌套 MAX 思路。聚合零行时会返回 NULL,并且仍会产生一行。对于第二高值问题,这是一种简洁的一行写法,已经满足 NULL 要求。
但需要注意:将纯 MAX 嵌套扩展到任意 N 会变得很难看,因此这种方法最适合第二高值这一特定情况。
SELECT MAX(salary) AS second_highest
FROM employee
WHERE salary < (SELECT MAX(salary) FROM employee);使用 COALESCE 提供回退值
如果您的环境能保证返回一行,但值可能因其他原因缺失,可以用 COALESCE 包裹结果,以提供一个明确的默认值。
请注意:只有在行已经存在时,COALESCE 才能发挥作用。它不会将空结果集转换为一行。因此,请将它与标量子查询包裹方法结合使用(该方法能保证返回一行),然后在需要使用不同于 NULL 的值(例如 0)时,对该值使用 COALESCE。
SELECT COALESCE((
SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 2
), 0) AS third_highest_or_zero;NOT 无法解决的问题
请警惕那些看似正确但实际上无效的修复方法:
- 直接在返回零行的查询外包裹
COALESCE没有作用;因为没有行可供COALESCE处理。 IFNULL/ISNULL与COALESCE存在相同的限制。- 添加
LIMIT 1也不会在没有符合条件的行时凭空创建一行。
行数问题必须通过标量子查询包裹方法或聚合来解决,不能只依靠 NULL 替换函数。
从两个薪资等级中请求第 3 高值
薪资为:500、500、300。不同的薪资只有 500 和 300,因此不存在第 3 高值。
- 使用 WHERE rnk = 3 的普通 DENSE_RANK:返回零行,不符合规范。
- 标量子查询包裹方法:内部查询什么也找不到,因此外层 SELECT 返回一行:
NULL。符合要求。 - COALESCE(..., 0):如果要求使用数值默认值,则返回一行:
0。
在面试中说明解题过程
通过清晰说明以下几点来争取分数:
- “直接查询返回的是空集,而不是 NULL,所以我会将它包裹在标量子查询中,以保证返回一行。”
- “没有匹配行的标量子查询会计算为 NULL,这正是要求的约定。”
- “如果您更希望得到 0 之类的默认值,而不是 NULL,我会在子查询外添加 COALESCE。”
这个问题的核心,就是证明您理解行数与值的语义区别。
整合所有内容
一种稳健且可参数化的“第 N 高值或 NULL”解决方案是:对不同薪资进行排名,在标量子查询中按排名 N 过滤,并让外层 SELECT 保证返回单行。
这个查询通过 DENSE_RANK 处理重复值,能够推广到任意 N;当 N 超过不同薪资的数量时,也会平稳地返回 NULL。
SELECT (
SELECT salary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employee
) t
WHERE rnk = :n
LIMIT 1
) AS nth_highest;快速检查
请思考行数与 NULL 值之间的区别。
回顾
当 N 超过可用的不同薪资数量时,普通排名查询会返回一个空集,而不是 NULL。
- 将第 N 高值查询包裹在外层 SELECT 中的标量子查询里,这样它始终会产生一行;没有值匹配时,该行的值为
NULL。 - 对于第二高值问题,MAX 嵌套 MAX 的形式无需额外处理即可返回
NULL。 - COALESCE 只有在行存在后才能替换值;它无法将零行转换为一行。
当面试官要求妥善处理 NULL 时,请始终区分行数和值。
常见问题解答
「不存在第 N 个值时返回 NULL」课时是免费的吗?
是的 — 「不存在第 N 个值时返回 NULL」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「不存在第 N 个值时返回 NULL」这节课中我会学到什么?
掌握面试官喜欢考查的极端情况:优雅地处理行数不足 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「不存在第 N 个值时返回 NULL」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 第二高薪资的五种写法
- 使用 DENSE_RANK 查找第 N 高值
- 各部门最高薪资者
- 不存在第 N 个值时返回 NULL