SQL 查询中的 NULL 值

本文经过各类 SQL 小例子,解释 NULL 值的用途和带来的问题。html

英语原文地址:mitchum.blog/null-values…web

做者:MITCHUMsql

翻译:高行行数据库

参考翻译文章:blog.csdn.net/lnotime/art…编程

小结:编程语言

  • SQL 里的 NULL 和其余编程语言里的 NULL 是彻底不一样的东西
  • 在 SQL 中 NULL 为未知

翻译水平有限,可能存在翻译不许确的地方,尽情谅解。网站

今天的帖子是关于 SQL 中的 NULL 值的,由个人朋友兼数据库向导 Kaley 提供。若是你想了解有关 SQL,Oracle 数据库以及使查询运行更快的更多信息,请访问他的网站ui


这是一个使不少萌新开发人员陷入困境的话题-SQL 查询中 NULL 值的概念。spa

每当你向数据库发出SQL查询时……你想知道一列中是否包含 NULL 值……编写查询以查到结果的正确方式是什么?.net

你应该使用这样的查询吗?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN = NULL
复制代码

要么!你应该使用这样的查询吗?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN IS NULL
复制代码

…答案是,你应该使用第二个查询(SOME_COLUMN IS NULL)。

下图为实际的查询例子 🌰

为何呢?

为何其余的比较都不用 IS 关键字呢?

若是咱们想知道一个字段是否等于 1,咱们可使用以下的 WHERE 子句:

WHERE SOME_COLUMN = 1
复制代码

那么为何咱们在IS关键字上使用 NULL 值呢?为何咱们须要区别对待 NULL ?

答案是这样的:在 SQL 中,NULL 表示“未知”的概念 _ _(所以 NULL 值表示“未知”值)。

1. Null 为未知

在大多数数据库中,NULL 和空字符串(由双撇号 "" 或 '' 表示)之间存在差别。

可是,并不是全部数据库都这样:例如,Oracle 数据库不容许你使用空字符串。任什么时候候 Oracle 数据库看到一个空字符串,它都会自动将空字符串转换为 NULL 值。

可是,对于大多数其余数据库,NULL 值与空字符串的处理方式不一样:

  • 空字符串被视为没有值的已知值**。**
  • 将 NULL 值视为未知值

举个例子,就好像问:美国总统西奥多·罗斯福的中间名是什么?

  • 一种答案多是:“嗯,我不知道西奥多·罗斯福的中间名是什么。”(此想法能够由 Theodore Roosevelt 的记录的 MIDDLE_NAME 列中的 NULL 值表示,即中间名字段为 NULL)
  • 另外一种答案多是**“西奥多·罗斯福总统实际上没有中间名。他的父母从未给他起过中间名,我知道的事实就是西奥多·罗斯福(Theodore Roosevelt)没有中间名。 **(你能够经过在 MIDDLE_NAME 列中输入一个空字符串或 '' 来表示,即中间名字段为空字符串)

Oracle 数据库是最显著的例外,其中这两个值实际上都将由 NULL 表示-除 Oracle 之外的大多数数据库对 NULL 和空字符串的处理方式都很是不一样。

只要你记得 NULL 值表明一个未知值,那么这将有助于你编写 SQL 查询,并帮助你解决使用 NULL 值可能遇到的一些棘手状况。

例如,若是你要使用这样的 WHERE 子句查询:

SELECT * FROM SOME_TABLE
WHERE 1 = 1
复制代码

该查询将返回行(假设 SOME_TABLE 不是空表!),由于表达式“ 1 = 1” 可证实是 true 的……它能够被证实是正确的。

若是我要说:

SELECT * FROM SOME_TABLE
WHERE 1 = 0
复制代码

而后数据库将看到此状况,并将“ 1 = 0”评估为 false(这意味着该查询将_永远不会_返回任何行)。

可是若是我要说:

SELECT * FROM SOME_TABLE
WHERE 1 = NULL
复制代码

数据库基本上是这样的:“我不知道这两个值(1 和咱们的黑盒 NULL 值)是否相等”……所以它不返回任何记录。

2. 三值逻辑

当 SQL 查询中有 WHERE 子句时,它能够具备三种不一样结果之一:

  • true(它将返回行)
  • false(不会返回行)
  • NULL(未知也不会返回行)

你可能会想,“好吧,既然数据库对这两个值的处理彻底相同,我为何要关心 false 和 null 之间的区别?”

好吧,让我告诉你哪里可能遇到麻烦:让咱们介绍一下 NOT() 条件。

若是你要说:

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 1)
复制代码

而后,数据库首先要求值 1 = 1,而后说:“好吧,那显然是对的。”

可是随后它将对其应用 NOT() 条件。“当 true 被 NOT() 修饰时,它变成了 false……因此 NOT() 条件致使咱们的 WHERE 子句在这里是 false 的。”

所以,上面的查询不会返回任何记录。

可是,若是你要说:

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 0)
复制代码

而后,数据库首先计算表达式 1 = 0,并说:“那显然是 false 的。”

可是而后它将应用 NOT() 条件,这将给咱们相反的结果,所以它变为 true

所以此查询将返回记录!

若是我发出如下查询怎么办?

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)
复制代码

数据库首先要评估 1 = NULL。(请记住,它将把 NULL 看成一个未知值!)

它会说:“我不能说 1 是否等于 NULL,由于我不知道 NULL(未知)值是什么。”

所以,它不会产生 true 的结果也不会产生 false 的结果 – 而是会产生 NULL(未知)结果。

NULL 结果将由 NOT() 运算符修饰。

每当你使用 NULL 并将其置于 NOT() 条件时……结果就是另外一个 NULL!(未知的反面是……嗯……另外一个未知)。

所以,NOT() 运算符对 null 条件不作任何事情。

因此这些查询中的……

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)
复制代码
SELECT * FROM SOME_TABLE
WHERE 1 = NULL
复制代码

…将不返回任何记录…即便它们是相反的!

3. NULL 和 NOT IN

若是我使用 WHERE 子句发出这样的查询:

SELECT * FROM SOME_TABLE
WHERE 1 IN (1, 2, 3, 4, NULL)
复制代码

…那么显然 WHERE 子句将是 true 的,因为 1 在咱们的 IN 列表中,因此该查询将返回记录…

可是若是我要说:

SELECT * FROM SOME_TABLE
WHERE 1 NOT IN (1, 2, 3, 4, NULL)
复制代码

那么显然这将是 false 的,该查询将永远不会返回记录,由于数字 1 出如今咱们的 IN 列表中,而且咱们说“ NOT IN”…

如今,若是我要说这样的话怎么办?

SELECT * FROM SOME_TABLE
WHERE 5 NOT IN (1, 2, 3, 4, NULL)
复制代码

此 WHERE 子句将永远不会返回任何记录,由于它不是真正的可证实(它不能被证实是 true 的)。数字 5 没有明确出如今“ IN”列表中 - 可是 5 可能在咱们的“黑盒” NULL 值内(数据库不必定知道 NULL 的值是什么)。

这将产生 NULL 结果(表示未知结果),所以 WHERE 子句永远不会返回任何记录。

这就是为何将 NULL 值等效为未知值很重要的缘由 - 每当你编写复杂的SQL查询时,它都会为你提供帮助。

但愿你如今已经准备好处理 SQL 查询中的 NULL 值!有关 SQL,Oracle 数据库以及使查询运行更快的更多信息,请访问  blog.tuningsql.com

资料

实际例子 🌰的 SQL 文件

CREATE TABLE `user` (
  `id` int(25) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(32) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (2, '小白', 1, '0', '333');
INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (3, 'white', 12, '0', '111');
INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (4, 'white', NULL, '0', '222');
复制代码

参考文章

神奇的 SQL 之温柔的陷阱 → 三值逻辑 与 NULL !

相关文章
相关标签/搜索