我知道它确实考虑了“ ”作为 NULL
,但这并不能告诉我为什么会出现这种情况。据我了解 SQL 规范,' '与 NULL
不同——一个是有效数据,另一个表示缺少相同的信息。
随意推测,但请指出是否是这种情况。如果甲骨文有任何人可以对此发表评论,那就太好了!
我相信答案是甲骨文非常非常古老。
早在 SQL 标准出现之前,Oracle 就做出了设计决定,即 VARCHAR
/VARCHAR2
列中的空字符串为 NULL
,并且只有一种 NULL 含义(有关系理论家会区分在从未被提示的数据、存在答案但用户不知道的数据、没有答案的数据等之间,所有这些都构成了NULL
的某种意义。
当 SQL 标准出现并同意 NULL
和空字符串是不同的实体时,已经有 Oracle 用户的代码假定两者是等价的。因此,Oracle 基本上只能选择破坏现有代码、违反 SQL 标准或引入某种初始化参数来改变潜在大量查询的功能。违反 SQL 标准 (IMHO) 是这三个选项中破坏性最小的。
Oracle 保留了 VARCHAR
数据类型在未来版本中更改以符合 SQL 标准的可能性(这就是为什么每个人都在 Oracle 中使用 VARCHAR2
,因为该数据类型的行为保证在未来保持不变) .
Tom Kyte 甲骨文副总裁:
零长度 varchar 被视为 NULL。 '' 不被视为 NULL。 '' 分配给 char(1) 时变为 ' ' (char 类型是空白填充字符串)。 '' 分配给 varchar2(1) 时变为 '',这是一个零长度字符串,而零长度字符串在 Oracle 中为 NULL(它不是长 '')
Oracle 文档提醒开发人员注意这个问题,至少可以追溯到版本 7。
Oracle 选择用“不可能值”技术来表示 NULLS。例如,数字位置中的 NULL 将存储为“负零”,这是一个不可能的值。计算产生的任何负零都将在存储之前转换为正零。
Oracle 还错误地选择将长度为零的 VARCHAR 字符串(空字符串)视为不可能的值,并且是表示 NULL 的合适选择。事实证明,空字符串远非不可能的值。甚至是字符串拼接操作下的身份!
Oracle 文档警告数据库设计人员和开发人员,Oracle 的某些未来版本可能会破坏空字符串和 NULL 之间的这种关联,并破坏任何依赖于该关联的代码。
除了不可能的值之外,还有一些技术可以标记 NULLS,但 Oracle 没有使用它们。
(我在上面使用“位置”这个词来表示行和列的交集。)
如果您像早期开发人员可能会做的那样考虑 Oracle,我怀疑这会更有意义 - 作为数据输入系统的美化后端。数据库中的每个字段都对应于数据输入操作员在其屏幕上看到的表单中的字段。如果操作员没有在字段中输入任何内容,无论是“生日”还是“地址”,那么该字段的数据就是“未知”。操作员无法指示某人的地址实际上是一个空字符串,而且这实际上没有多大意义。
According to official 11g docs
Oracle 数据库当前将长度为零的字符值视为空值。但是,在未来的版本中,这可能不会继续存在,Oracle 建议您不要将空字符串视为与 null 相同。
可能的原因
val IS NOT NULL 比 val != '' 更具可读性 无需检查两个条件 val != '' 和 val IS NOT NULL
val <> ''
已排除 NULL
。也许您的意思是 val = '' OR val IS NULL
。但是不比较为 NULL 的空字符串是有用的!
空字符串与 NULL 相同,只是因为与两者(空字符串和 null)不同的情况相比,它是“较小的邪恶”。
在 NULL 和空字符串不相同的语言中,必须始终检查这两个条件。
not null
约束并仅检查空字符串。
WHERE Field <> ''
仅当字段不为 NULL 且不为空时才返回 true,在具有空字符串的 ANSI 行为的数据库上。
NULL !== NULL
但 '' === ''
,所以我认为这不是较小的邪恶。它增加了混乱。
书中的例子
set serveroutput on;
DECLARE
empty_varchar2 VARCHAR2(10) := '';
empty_char CHAR(10) := '';
BEGIN
IF empty_varchar2 IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
END IF;
IF '' IS NULL THEN
DBMS_OUTPUT.PUT_LINE(''''' is NULL');
END IF;
IF empty_char IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
ELSIF empty_char IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
END IF;
END;
因为不将其视为 NULL 也不是特别有用。
如果您在 Oracle 上在这方面犯了错误,您通常会立即注意到。但是,在 SQL Server 中,它似乎可以工作,并且仅当有人输入空字符串而不是 NULL 时才会出现问题(可能来自 .net 客户端库,其中 null 与“”不同,但您通常将它们视为相同)。
我并不是说 Oracle 是对的,但在我看来,这两种方式都差不多一样糟糕。
事实上,我在处理 Oracle 时遇到了困难,包括无效的日期时间值(不能打印、转换或任何东西,只能用 DUMP() 函数查看),这些值被允许插入数据库,显然是通过一些错误客户端作为二进制列的版本!保护数据库完整性就这么多!
Oracle 处理 NULL 链接:
http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/
http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html
首先,Oracle 并不总是将 null 和 null 字符串视为相同的。根据定义,空字符串是不包含字符的字符串。这与 null 完全不同。根据定义,NULL 是没有数据。
五六年前,Oracle 对 null 字符串的处理方式与 null 不同。虽然,像 null 一样,null string 等于所有内容并且不同于所有内容(我认为 null 很好,但 null 字符串完全错误),至少 length(null string) 会返回 0,因为它应该返回 null string零长度的字符串。
目前在 Oracle 中,length(null) 返回 null,我猜是可以的,但是 length(null string) 也返回 null,这是完全错误的。
我不明白他们为什么决定开始同等对待这两个不同的“价值观”。它们意味着不同的东西,程序员应该有能力以不同的方式对它们采取行动。他们改变了他们的方法的事实告诉我,他们真的不知道应该如何对待这些价值观。
VARCHAR
字段可以有值(零个或多个字符)或无值 (NULL),句号。
NULL
和 null 值字符串之间从来没有任何区别,这样的区别是没有意义的。恐怕这个答案完全是幻想。
''
隐式 转换为 VARCHAR2、such ascast('' as char(1)) is null
which is... surprisingly TRUE 时,会出现最令人困惑的情况