MySQL 学习笔记(11)— NULL 与逻辑运算符、NULL 空值比较、空值排序、空值函数、GROUP BY 子句和 DISTINCT运算符的空值

参考链接:

https://gitbook.cn/gitchat/column/undefined/topic/5db92b4ea9c3a53bc3800efc

1. 空值与三值逻辑

SQL 中的空值( NULL )是一个特殊的值,代表了缺失/未知的数据或者不适用的情况。对于大多数的编程语言而言,逻辑运算的结果只有两种情况:真( Ture )或者假( False )。但是对于 SQL 而言,逻辑运算结果存在三种情况:真、假或者未知( Unknown )。对于 SQL 查询中的 WHERE 条件,只有结果为真的数据才会返回,结果为假或者未知都不会返回。

因此, SQL 中的逻辑运算符 ANDOR 以及 NOT 的结果也存在三种情况。

1.1 AND 操作符的逻辑真值表


AND 操作符TRUEFALSENULL
TRUETRUEFALSENULL
FALSEFALSEFALSEFALSE
NULLNULLFALSENULL

AND 操作符只有当两边的结果都为真时,最终结果才为真;否则结果为假或者未知,意味着不返回结果。

1.2 OR 操作符的逻辑真值表


OR 操作符TRUEFALSENULL
TRUETRUETRUETRUE
FALSETRUEFALSENULL
NULLTRUENULLNULL

OR 操作符只要有一个结果为真,最终结果就为真;否则结果为假或者未知,意味着不返回结果。


1.3 NOT 操作符的逻辑真值表


NOT 操作符
TRUEFALSE
FALSETRUE
NULLNULL

NOT 操作符用于取反操作,对于未知结果取反结果还是未知。

2. 空值比较与运算

任何值与 NULL 值进行比较时,结果无法确认是真还是假。以下比较运算的结果都是未知:

NULL = 0
NULL != 0
NULL > 1
NULL = NULL
NULL != NULL

NULL 等于 NULL 的运算结果未知, NULL 不等于 NULL 的运算结果也未知。因此,为了判断某个值是否为空,SQL 提供了 IS NULLIS NOT NULL 谓词:

另外,当表达式或者函数涉及 NULL 值时,通常结果也是 NULL 值。例如,以下运算的结果都为空:

SELECT 100 + NULL, UPPER(NULL)
  FROM employee
 WHERE emp_id = 1;

100 + NULL|UPPER(NULL)|
----------|-----------|
          |           |

不过也存在一些例外,比如:

SELECT CONCAT('hello', NULL)
  FROM employee
 WHERE emp_id = 1;

该查询只有在 MySQL 返回 NULLCONCAT 函数在 OracleSQL Server 以及 PostgreSQL 中将 NULL 当作空字符串处理,返回字符串“hello”。由于不同数据库采取了不同的实现,因此在使用时这些函数时需要小心。

3. 空值排序

由于 SQL 标准没有提出明确要求空值的排序规则,导致在不同的数据库中存在两种空值排序方式:

  • OraclePostgreSQL ,升序时空值排在最后,降序时空值排在最前;同时支持使用 NULLS FIRSTNULLS LAST 指定空值的顺序;
  • MySQLSQL Server ,升序时空值排在最前,降序时空值排在最后。

4. 空值函数

SQL 中定义了两个与空值转换相关的函数: NULLIFCOALESCE

4.1 NULLIF

NULLIF(expr1, expr2) 函数接受 2 个参数,如果第一个参数等于第二个参数,返回 NULL ;否则,返回第一个参数的值。

SELECT NULLIF(1, 2),
       NULLIF(3, 3)
  FROM employee
 WHERE emp_id = 1;

NULLIF(1, 2)|NULLIF(1, 1)|
------------|------------|
           1|      [NULL]|

因为 1 不等于 2,该查询的第一列结果为 1;因为 3 等于 3,第二列结果为 NULL

NULLIF 函数的一个常见用途是防止除零错误:

-- 除零错误
SELECT *
  FROM employee
 WHERE 1 / 0 = 1;

-- 避免除零错误
SELECT *
  FROM employee
 WHERE 1 / NULLIF(0 , 0) = 1;

第一个查询中被除数为 0,出现除零错误(MySQL 可能不会提示错误);第二个查询使用 NULLIF 函数将被除数 0 转换为 NULL ,整个结果为 NULL

4.2 COALESCE

COALESCE(expr1, expr2, expr3, ...) 函数接受一个参数列表,并且返回第一个非空的参数;如果所有参数都为空,返回 NULL

以下示例用于查询员工的总收入:

SELECT emp_name,
       salary*12 + bonus AS "年收入",
       salary*12 + COALESCE(bonus, 0) AS "年收入"
  FROM employee
 WHERE emp_id <= 6;

emp_name|年收入     |年收入    |
--------|---------|---------|
刘备      |370000.00|370000.00|
关羽      |322000.00|322000.00|
张飞      |298000.00|298000.00|
诸葛亮    |296000.00|296000.00|
黄忠      |   [NULL]| 96000.00|
魏延      |   [NULL]| 90000.00|

该查询中的第三列利用 COALESCE 函数将奖金为空的数据转换为 0,得到了正确的年收入。

4.3 专有函数

除了 SQL 标准中定义的表达式之外,许多数据库还实现了一些类似的扩展函数:

  • Oracle 提供了 NVL(expr1, expr2) 以及 NVL2(expr1, expr2, expr3) 函数;
  • MySQL 提供了 IFNULL(expr1, expr2) 以及 IF(expr1, expr2, expr3) 函数;
  • SQL Server 提供了 ISNULL(expr1, expr2) 函数。

MySQL 提供了 IFNULL(expr1, expr2) 函数。该函数用于返回第一个非空的参数值,相当于只有两个参数的 COALESCE 函数。以下查询也返回员工的总收入:

-- MySQL 实现
SELECT emp_name,
       salary*12 + IFNULL(bonus, 0) AS "年收入"
  FROM employee
 WHERE emp_id <= 6;

MySQL 提供了类似于 NVL2IF(expr1, expr2, expr3) 函数。它接受三个参数,如果第一个参数为真(expr1 <> 0 并且 expr1 不为空),返回第二个参数的值;否则,返回第三个参数的值。以下查询同样返回员工的总收入:

-- MySQL 实现
SELECT emp_name,
       IF(bonus, salary*12 + bonus, salary*12) AS "年收入"
  FROM employee
 WHERE emp_id <= 6;

5. 分组与聚合函数中的空值

GROUP BY 子句、 DISTINCT 运算符将所有的空值视为相同,因此将它们分为一组。虽然许多员工没有奖金,以下查询的结果中只有一个 NULL 值:

SELECT DISTINCT bonus
  FROM employee;

SELECT bonus
  FROM employee
 GROUP BY bonus;

该查询的结果如下:

bonus   |
--------|
10000.00|
 8000.00|
  [NULL]|
 5000.00|
 6000.00|
 2000.00|
 1500.00|

6. NOT IN 中的空值

IN 操作符用于查询位于列表之中的数据, NOT IN 用于查询不位于列表中的数据。以下是一个 IN 操作符的示例:

SELECT emp_id
  FROM employee
 WHERE emp_id IN (1, 2, 3, NULL);

emp_id|
------|
     1|
     2|
     3|

该查询的结果返回了 3 条记录,因为他们的员工编号位于列表之中。接下来使用 NOT IN 查询不在列表中的数据:

SELECT emp_id
  FROM employee
 WHERE emp_id NOT IN (1, 2, 3, NULL);

emp_id|
------|

该查询没有返回任何结果。原因在于 IN 操作符使用等号( = )依次与列表中的数据进行比较,该查询等价于以下形式:

SELECT emp_id
  FROM employee
 WHERE emp_id != 1
   AND emp_id != 2
   AND emp_id != 3
   AND emp_id != NULL;

任何值与 NULL 比较的结果都是未知;因此没有数据满足该条件,也就没有返回结果。

为了避免各种情况下空值可能带来的问题,可以利用 SQL 提供的空值处理函数将 NULL 值转换为其他数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wohu007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值