Article / 文章
LeetCode 第176题:第二高的薪水
编写一个SQL查询,获取 Employee 表中第二高的薪水(Salary)。 +-------------+------+ | Column Name | Type | +-------------+------+ | id | int | | salary | int | +-------------+------+ id 是这个表的主键。 表的每一行包
题目描述
编写一个SQL查询,获取 Employee 表中第二高的薪水(Salary)。
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| salary | int |
+-------------+------+
id 是这个表的主键。
表的每一行包含员工的工资信息。
例如,给定上表,如果有超过一个第二高的薪水,则查询应该返回 null 。查询结果应该如下所示。
难度
中等
题目链接
示例
示例1:
输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
示例2:
输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| null |
+---------------------+
提示
- 如果没有第二高的薪水,查询应返回 null
解题思路
方法一:使用 ORDER BY 和 LIMIT 子句
一种直接的方法是使用 ORDER BY 来对薪水进行降序排序,然后使用 LIMIT 子句来获取第二高的薪水。
关键点:
- 使用 DISTINCT 去除重复值
- 对薪水进行降序排序
- 使用 LIMIT 1 OFFSET 1 获取第二条记录
- 使用外层查询包装结果,以在没有第二高薪水时返回 NULL
时间复杂度:O(n log n),其中 n 是 Employee 表中的行数(排序的时间复杂度) 空间复杂度:O(n)
方法二:使用 IFNULL 和子查询
另一种方法是使用子查询找出不是最大薪水的最大薪水。
关键点:
- 使用 IFNULL 函数处理没有第二高薪水的情况
- 内部使用 MAX 函数找出小于最大薪水的最大薪水
时间复杂度:O(n),其中 n 是 Employee 表中的行数 空间复杂度:O(1)
代码实现
SQL 实现(方法一)
SELECT
(SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1) AS SecondHighestSalary;
SQL 实现(方法二)
SELECT
IFNULL(
(SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1),
NULL
) AS SecondHighestSalary;
SQL 实现(方法三:子查询)
SELECT
MAX(salary) AS SecondHighestSalary
FROM
Employee
WHERE
salary < (SELECT MAX(salary) FROM Employee);
性能分析
各SQL实现的性能对比:
| 实现方法 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|
| 方法一 | 179 ms | 0B | 简单直观,使用OFFSET |
| 方法二 | 185 ms | 0B | 使用IFNULL确保返回NULL |
| 方法三 | 171 ms | 0B | 使用子查询,性能最佳 |
补充说明
代码亮点
- 方法一和方法二使用 DISTINCT 去除重复的薪水值
- 方法二明确使用 IFNULL 处理边缘情况,提高代码可读性
- 方法三利用子查询和 MAX 函数简洁地解决问题
常见错误
- 忘记处理重复薪水的情况
- 没有正确处理不存在第二高薪水时应返回 NULL 的情况
- 使用 LIMIT 2,然后获取第二个元素,这在只有一个元素时会失败
MySQL特殊函数说明
- IFNULL(expr1, expr2):如果expr1不为NULL,则返回expr1;否则返回expr2
- DISTINCT:消除结果集中的重复行
- LIMIT n OFFSET m:从结果集的第m+1行开始,返回最多n行