MySQL 解决查询NULL的问题

时间:2022-07-23
本文章向大家介绍MySQL 解决查询NULL的问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意分析

题目很简单:有一个 Employee 表,表里有两个字段:id(职工号)、salary(工资)。要求查询第二大的工资数,展示项名为:SecondHighestSalary

难点: 当第二大的工资不存在的时候,查询结果为 NULL

解题思路

首先我们先忽略工资不存在的情况,只解决“第二大”这个问题。所谓“第二大”,因为通常我们比较容易拿到“第一大”(即最大值),所以我们转换一下概念,即去掉“第一大”后,剩下的“第一大”即“第二大”。确定这一概念之后,便很好做了。常见的解决方法如下:

第一种方式,分解二个步骤,代码如下:

-- 按 salary 倒序,取前两个值
SELECT DISTINCT(salary) FROM employee
ORDER BY salary DESC
LIMIT 2;

-- 将上述结果 按 salary 升序,取第一个值
SELECT t.salary AS 'SecondHighestSalary'
FROM (
    SELECT DISTINCT salary
    FROM employee
    ORDER BY salary DESC
    LIMIT 2
) t
ORDER BY t.salary ASC
LIMIT 1;

第二种思路,和上面类似,只是倒序后,直接利用 MIN() 方法,取最小值:

SELECT MIN(t.salary) AS 'SecondHighestSalary'
FROM (
    SELECT DISTINCT salary
    FROM employee
    ORDER BY salary DESC
    LIMIT 2
) t

第三种思路,也是分三步骤,先找到最大值,然后从全集里排除最大值,最后从子集里找最大值:

-- 查找最大值
SELECT MAX(salary) FROM employee;

-- 从全集里排除最大值
SELECT salary FROM employee WHERE salary != (
    SELECT MAX(salary) FROM employee
)

-- 从上面得到的子集里,找最大值
SELECT MAX(salary) FROM employee WHERE salary != (
    SELECT MAX(salary) FROM employee
)

第四种思路,利用 limit offset,limit 表示取多少个值,offset 表示偏移量,所以代码如下:

SELECT DISTINCT(salary) AS SecondHighestSalary FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1;

接着,我们来解决当“第二大”不存在时,需要返回 NULL 的问题。我们可以先自己创建 table,然后插入数据,执行上面的语句,当然也可以在 leetcode 上进行 debug。

可以发现第一和第二种思路,当数据不存在时,是有 bug 的,因为取最小值和取第一个值,都会取到一个值,除非整个 table 数据都是空的。这两种思路暂时排除(后面也会给出这两种思路下的解决方法)。

第三种思路,执行一下,结果很happy,符合题目要求,即便是数据不存在时,也会返回 NULL,好了,你已经完成了这个题目。

第四种思路,执行一下,当数据不存在时,返回的结果集为 空,并没有返回 NULL。

这里我们需要了解两个知识点,首先,对于 max()、min()、sum() 聚合函数,当值不存在时,会返回 NULL,因此我们的第三种思路可以满足题目要求。其次,SELECT 结果集; 可满足要求。它等价于 SELECT NULL;

因此我们的第四种方式,可写为:

SELECT (
    SELECT DISTINCT salary AS SecondHighestSalary
    FROM employee
    ORDER BY salary DESC
    LIMIT 1, 1
) AS SecondHighestSalary;

扩展

如果我们不知道 MAX 和 SELECT 结果集 这两种方式,有没有办法做出来呢?当然也是有的。也就是我们去扩展上面说到的第一和第二种思路,通过结合 LEFT JOIN 或 RIGHT JOIN。为什么会想到 LEFT JOIN 呢,很明显,不存在的结果却需要显示为 NULL,这很符合 LEFT JOIN 或 RIGHT JOIN 的特质。直接上代码:

SELECT if(m.salary2 IS NULL, NULL, m.salary1) AS SecondHighestSalary
FROM (
    SELECT t1.salary AS 'salary1', t2.salary AS 'salary2'
    FROM employee t1
        LEFT JOIN (
            SELECT salary
            FROM employee
            ORDER BY salary DESC
            LIMIT 1
        ) t2
        ON t1.salary < t2.salary
    ORDER BY t1.salary DESC
    LIMIT 2
) m
ORDER BY m.salary1 ASC
LIMIT 1