Oracle中Null和无值的区别

以Leetcode第176题“第二高的薪水”为例。

Oracle中Null和无值的区别_第1张图片
首先说一下这道题最容易理解、最容易实现的解法,就是比最大值小的值里最大的值。

SELECT MAX(salary) AS SecondHighestSalary
FROM Employee
WHERE salary < (SELECT MAX(salary) 
                FROM Employee)

通过这道题目,我来说明一下,什么时候结果集显示的是null,什么时候是空。下面这个是我们的测试用例,也就是只有一个值,第二高的薪水也就是null。
在这里插入图片描述
用上面的语句搜索,结果是下面这样的。
Oracle中Null和无值的区别_第2张图片
如果你把SQL改成下面这样,也就是去掉MAX函数,结果就变成了空。可以看到输出为null与MAX有关系。

SELECT salary AS SecondHighestSalary
FROM Employee
WHERE salary < (SELECT MAX(salary) 
                FROM Employee)

Oracle中Null和无值的区别_第3张图片
我们在利用这个题目试验一些别的东西,比如说取rownum为2的行,对于这个测试用例应该为null,可以发现输出的结果为空。(这道题不能这么做,因为还有重复值的问题,只是举个例子)

SELECT a.salary AS SecondHighestSalary
FROM (SELECT rownum r, e.*
      FROM Employee e) a
WHERE a.r = 2

Oracle中Null和无值的区别_第4张图片
如果我们像上面一样加个MAX函数,输出结果就会为null。

SELECT MAX(a.salary) AS SecondHighestSalary
FROM (SELECT rownum r, e.*
      FROM Employee e) a
WHERE a.r = 2

Oracle中Null和无值的区别_第5张图片


如果我们在套一个SELECT,也可以输出为null。

SELECT(
    SELECT a.salary
    FROM (SELECT rownum r, e.*
          FROM Employee e) a
    WHERE a.r = 2
) AS SecondHighestSalary
FROM dual

Oracle中Null和无值的区别_第6张图片
对于MySQL来说也是这样的,只不过由于语法原因,它不要FROM dual。这个评论区也有人询问,这个解释我觉得没解释出什么,但不知道为什么这么多赞。
Oracle中Null和无值的区别_第7张图片
Oracle中Null和无值的区别_第8张图片


那NVL不行吗?
可以看到这种方式也是输出为空。

SELECT NVL(a.salary, null) AS SecondHighestSalary
FROM (SELECT rownum r, e.*
      FROM Employee e) a
WHERE a.r = 2

Oracle中Null和无值的区别_第9张图片
但是如果你像下面这么写,输出的则是null(确实是由于NVL而输出的,把NVL第二个参数改成别的输出的内容也会变),很奇怪。这也是这道题目Oracle解法大部分人都采用的办法。包括MySQL也是如此。我也不知道为什么,网络上也查不到,只能强行理解SELECT这个语句,放到一个函数里,自己可能也相当于是一个函数(因为NVL只会获取null,所以说明里面SELECT出来就已经是null了,也可以发现,NVL对于这道题没啥用,直接SELECT一个SELECT就可以了)。

SELECT NVL((SELECT a.salary
            FROM (SELECT rownum r, e.*
                  FROM Employee e) a
            WHERE a.r = 2), null) AS SecondHighestSalary
FROM dual

Oracle中Null和无值的区别_第10张图片
MySQL的例子:
Oracle中Null和无值的区别_第11张图片

我找了两道我用过NVL的题目,发现一个是左连接,一个全连接,它们这种在JOIN时没有值会直接补null,所以用NVL就可以。

SELECT name, NVL(SUM(distance), 0) AS travelled_distance
FROM Users u LEFT JOIN Rides r
  ON u.id = r.user_id
GROUP BY u.id, u.name
ORDER BY travelled_distance DESC, u.name
----------------------------------------------------------
SELECT NVL(e.employee_id, s.employee_id) AS employee_id
FROM Employees e FULL OUTER JOIN Salaries s
  ON e.employee_id = s.employee_id
WHERE e.name IS NULL OR s.salary IS NULL
ORDER BY 1

总结

如果一个查询是没有结果的,你如果想让输出是null,有两种方式

  1. 用一个函数,像MAX、MIN等,去包住这个SELECT的值。该怎么理解呢?我也不知道,我觉可以理解为一个函数的参数为空,输出结果就是null。
  2. 你可以在这个SELECT的外面在套一个SELECT,该怎么理解呢?我觉得就是SELECT空,输出就是null。
  3. 额外说一下NVL,NVL是遇见null才会起作用的,遇见空是不起作用的。如果想让它起作用可以在NVL里包一个SELECT语句,强行理解,可以说把这个语句变成“函数”,这样就会输出null。
补充

这个文章是说MySQL里ifnull的,也证明了我的猜想:地址。

你可能感兴趣的:(Oracle,oracle,数据库)