第 N 高的薪水:把排名写进函数里
LeetCode 177 · 自定义函数、窗口排名、参数化查询
面试怎么回答
本质是「去重后按名次取值」。我会先对薪水去重,再用 DENSE_RANK 或 RANK 排名取第 N 档;放在函数里时,结果作为标量返回,不存在时自然是 NULL。如果用 LIMIT 写,要注意 MySQL 的 OFFSET 不能写表达式,得先在函数体里把 N 减一。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
写一个函数,传入 N,返回员工表里第 N 高的薪水(相同薪水算同一档)。不存在第 N 高时返回 NULL。
表结构
- Employee:Id(主键)、Salary
思路
和第二高的思路一样,只是名次变成参数。原解法先按薪水 GROUP BY 去重,再用 RANK 排名,取排名等于 N 的那一档;因为已经去重,RANK 和 DENSE_RANK 在这里结果相同。也可以在函数里先 SET N = N - 1,再用 LIMIT 1 OFFSET N,因为 MySQL 的 LIMIT 不能直接写表达式。
参考解法
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
RETURN (
SELECT IFNULL(
(select salary
from(
select salary,
rank() over(order by salary desc) rk
from Employee
group by salary
)t1
where rk=N),NULL) SecondHighestSalary
);
END
另一种写法:LIMIT 版本,先在函数里把 N 减 1
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
SET N = N - 1;
RETURN (
SELECT DISTINCT Salary FROM Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET N
);
END
易错点
- 没去重就用 RANK:两个并列第一时第二名会被跳过,得到错误的档位。
- MySQL 的 LIMIT/OFFSET 不支持
N-1这种表达式,要先在函数体里算好再用。