我知道它将空格字符' '视为NULL
,但这并没有告诉我为什么会这样。据我了解SQL规范,' '并不等同于NULL
——一个是有效的数据值,而另一个则表示缺少相同的信息。
你可以自由猜测,但请指出是否如此。如果有任何来自Oracle的人可以对此发表评论,那将非常棒!
我知道它将空格字符' '视为NULL
,但这并没有告诉我为什么会这样。据我了解SQL规范,' '并不等同于NULL
——一个是有效的数据值,而另一个则表示缺少相同的信息。
你可以自由猜测,但请指出是否如此。如果有任何来自Oracle的人可以对此发表评论,那将非常棒!
我认为答案是Oracle非常古老。
在 SQL 标准出现之前的古老时期,Oracle 做了一个设计决策:在 VARCHAR
/VARCHAR2
字段中,空字符串等同于 NULL
,且只有一种 NULL 的含义(有关系理论家会区分从未被提示过的数据、用户不知道答案但存在的数据、没有答案的数据等,所有这些都构成某种 NULL
含义)。
当 SQL 标准出现并同意 NULL
和空字符串是不同的实体时,已经存在一些假定二者相等的 Oracle 用户代码。所以,Oracle 基本上只能选择破坏现有代码、违反 SQL 标准,或引入某种初始化参数来改变可能大量查询的功能。在这三个选项中,违反 SQL 标准(在我看来)是最不具破坏性的。
Oracle 保留了 VARCHAR
数据类型在将来的版本中遵循 SQL 标准的可能性(这就是为什么每个人在 Oracle 中使用 VARCHAR2
,因为该数据类型的行为保证将来保持不变)。
Tom Kyte Oracle副总裁:
一个长度为零的varchar被视为NULL。
''不被视为NULL。
当''被赋值给char(1)时,它变成了' '(char类型是空格填充的字符串)。
当''被赋值给varchar2(1)时,它变成了'',这是一个长度为零的字符串,在Oracle中,一个长度为零的字符串是NULL(它不再是'')。
''
被隐式转换为 VARCHAR2 时,例如 cast('' as char(1)) is null
,这...居然是真的(参见链接)。 - seheOracle文档警告开发人员存在这个问题,至少可以追溯到版本7。
Oracle选择使用“不可能的值”技术来表示NULLS。例如,数字位置中的NULL将被存储为“负零”,这是一个不可能的值。任何由运算产生的负零都将在存储之前转换为正零。
Oracle还错误地选择认为长度为零(空字符串)的VARCHAR字符串是一个不可能的值,并且是表示NULL的合适选择。事实证明,空字符串远非不可能的值。甚至是字符串连接操作下的身份元素!
Oracle文档警告数据库设计人员和开发人员,未来的某个版本可能会打破空字符串和NULL之间的关联,并破坏任何依赖该关联的代码。
除了不可能的值之外,有一些标记NULLS的技术,但Oracle没有使用它们。
(我在上面使用“位置”一词来表示行和列的交叉点。)
如果您把Oracle看作早期开发人员可能会这样做的方式-作为数据输入系统的后端,我认为这个问题就更有意义了。 数据库中的每个字段都对应着数据输入操作员在屏幕上看到的表单中的一个字段。 如果操作员没有在字段中输入任何内容,无论是“出生日期”还是“地址”,那么该字段的数据就是“未知的”。 没有办法让操作员指示某人的地址实际上是空字符串,而且这也没有太多意义。
目前,Oracle数据库将长度为零的字符值视为null。然而,在未来的版本中可能不再如此,Oracle建议您不要将空字符串视为null。
可能的原因
val IS NOT NULL
比val != ''
更易读 val != '' and val IS NOT NULL
val <> ''
已经排除了NULL
。也许您的意思是val = '' OR val IS NULL
。但是,不与NULL进行比较的空字符串是有用的! - ErikE空字符串与NULL相同,只是因为当这两种情况不同时,它是“较小的恶”。
在NULL和空字符串不同的语言中,必须始终检查这两个条件。
WHERE Field <> ''
才会返回true,在具有ANSI行为的数据库中,空字符串也会被视作非空。 - user565869NULL !== NULL
,但 '' === ''
,所以我认为这不是较小的罪恶。它会增加混淆。 - Tomáš Fejfar书中的例子
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并不总是将null和空字符串视为相同的。按照定义,空字符串是不包含任何字符的字符串。这与null完全不同。null是数据的缺失。
大约五六年前,Oracle对待空字符串与null的方式是不同的。虽然像null一样,空字符串等于所有值且不同于所有值(我认为对于null来说这是可以接受的,但对于空字符串来说完全错误),但至少length(null string)会返回0,因为空字符串是长度为零的字符串。
目前在Oracle中,length(null)返回null,我想这还可以接受,但length(null string)也返回null,这是完全错误的。
我不明白为什么他们决定开始将这两个不同的“值”视为相同。它们意味着不同的事情,程序员应该有能力以不同的方式对待它们。他们改变方法的事实告诉我,他们真的不知道如何处理这些值。
VARCHAR
字段可以有一个值(零个或多个字符)或没有值(NULL),就是这样。 - user565869NULL
和空值字符串,这种区分毫无意义。恐怕这个答案完全是虚构的。 - William Robertson事实上,我在处理Oracle时遇到了一系列困难,包括无效的日期时间值(无法打印、转换或执行任何操作,只能通过DUMP()函数查看),这些值竟然可以被插入到数据库中,显然是通过某个带有二进制列的版本客户端出现了故障!这样就无法保护数据库完整性!
Oracle对NULL的处理链接:
http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/
http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html