在大多数SQL实现中,与标准编程语言相反,为什么x !=null不返回true?



让我们假设x是某个变量,它具有除 null 以外的任何值,例如 4。以下表达式应返回什么?

x != null

在我使用过的几乎所有编程语言(C#,Javascript,PHP,Python)中,这个表达式或该语言中的等效表达式的计算结果为true

另一方面,SQL实现似乎都以完全不同的方式处理这个问题。如果NULL不等式运算符的一个或两个操作数,则将返回NULLFalse。这基本上与大多数编程语言使用的行为相反,对我来说非常不直观。

为什么 SQL 中的行为是这样的?关系数据库逻辑是什么使null的行为与通用编程中的行为大不相同?

大多数编程语言中的 null 被认为是"已知的",而 SQL 中的 NULL 被认为是"未知的"。

  • 因此X == null将 X 与已知值进行比较,结果是已知的(真或假)。
  • 但是X = NULL将 X 与未知值进行比较,结果是未知的(即再次为 NULL)。因此,我们需要一个特殊的操作员IS [NOT] NULL来测试它。

我猜这种 NULL 的动机至少有一部分是外键的行为。当外键的子终结点为 NULL 时,它不应匹配任何父级,即使父级为 NULL(如果父级是 UNIQUE 而不是主键,则可能)。不幸的是,这带来的陷阱比它解决的要多得多,我个人认为SQL应该走"已知"null的路线,并完全避免这种猴子业务。

甚至发明者或关系模型的E. F. Codd后来也指出,传统的NULL 不是最优的。但由于历史原因,我们几乎被困住了。

原因是相等的概念不适用于 null。 说这个 null 等于或不等于这个另一个 null 在逻辑上是不正确的。

所以,出于理论原因,这一切都很好,但为了方便起见,为什么SQL不允许你说(x != null)?

嗯,原因是因为有时你想以不同的方式处理空值。例如,如果我说(列 A = 列 B),如果两列都为 null,是否应该返回 true?如果我说(列 A != 列 B) - 当 A 列为"a"且 B 列为空时,以及当 A 列为"a"且列 B 为"b"时,它是否应该给出相同的结果?

制作SQL的人认为区分很重要,所以他们写它是为了区别对待这两种情况。

维基百科关于此的页面有一个相当不错的文章 - http://en.wikipedia.org/wiki/Null_%28SQL%29

在SQL引擎中,通常不使用"="运算符,而是使用"IS",这使得它更加直观。

SELECT 4 IS NULL FROM dual;
> 0

SELECT 4 IS NOT NULL FROM dual;
> 1

NULL 不代表空指针,它根本不是同一个概念。sql NULL 是一个我不知道值标志,它不是"没有指针"标志。你只是不应该比较它们,它们不应该以相同的方式使用。这是非常不直观的,你是对的,他们应该以不同的方式命名。

在SQL中,NULL表示"未知值"。

如果你说 x != NULL,你说的是"x 的值是否不等于未知值"。好吧,由于我们不知道未知值是什么,我们不知道x是否等于它。所以答案是"我不知道"。

同样地:

x = NULL OR 1=2    -- Unknown. 1=2 is not true, but we don't know about x=NULL
x = NULL OR 1=1    -- True. We know that at least 1=1 is true, so the OR is fulfulled regardless.
x = NULL AND 1=1   -- Unknown. We want them both to be true to fulful the AND
x = NULL AND 1=2   -- False. We know 1=2 is false, so the AND is not fulfilled regardless.

-- Neither statement will select rows where x is null
select x from T where x = 1
select x from T where x != 1

检查 null 的唯一方法是特别询问"我们真的不知道 x 的值是多少吗"。它有一个是或否的答案,并使用IS关键字。

如果只想将 null 视为零或其他值,则可以使用 COALESCEISNULL 函数。

COALESCE(NULL, 1)  -- 1
COALESCE(NULL, NULL, 1) -- Also 1
COALESCE(x, y, z, 0) -- x, unless it is null, then y, unless it is null, then z, unless it is null in which case 0.

最新更新