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 。查询结果应该如下所示。

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例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 子句来获取第二高的薪水。

关键点:

  1. 使用 DISTINCT 去除重复值
  2. 对薪水进行降序排序
  3. 使用 LIMIT 1 OFFSET 1 获取第二条记录
  4. 使用外层查询包装结果,以在没有第二高薪水时返回 NULL

时间复杂度:O(n log n),其中 n 是 Employee 表中的行数(排序的时间复杂度) 空间复杂度:O(n)

方法二:使用 IFNULL 和子查询

另一种方法是使用子查询找出不是最大薪水的最大薪水。

关键点:

  1. 使用 IFNULL 函数处理没有第二高薪水的情况
  2. 内部使用 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 使用子查询,性能最佳

补充说明

代码亮点

  1. 方法一和方法二使用 DISTINCT 去除重复的薪水值
  2. 方法二明确使用 IFNULL 处理边缘情况,提高代码可读性
  3. 方法三利用子查询和 MAX 函数简洁地解决问题

常见错误

  1. 忘记处理重复薪水的情况
  2. 没有正确处理不存在第二高薪水时应返回 NULL 的情况
  3. 使用 LIMIT 2,然后获取第二个元素,这在只有一个元素时会失败

MySQL特殊函数说明

  • IFNULL(expr1, expr2):如果expr1不为NULL,则返回expr1;否则返回expr2
  • DISTINCT:消除结果集中的重复行
  • LIMIT n OFFSET m:从结果集的第m+1行开始,返回最多n行

相关题目