ChatGPT解决这个技术问题 Extra ChatGPT

为什么 Oracle 9i 将空字符串视为 NULL?

我知道它确实考虑了“ ”作为 NULL,但这并不能告诉我为什么会出现这种情况。据我了解 SQL 规范,' '与 NULL 不同——一个是有效数据,另一个表示缺少相同的信息。

随意推测,但请指出是否是这种情况。如果甲骨文有任何人可以对此发表评论,那就太好了!

随意猜测?不知何故,我认为这不会为您提供最好的答案。
我想不会,但我不确定这个主题是否有任何确定性,所以我想我会打开门。到目前为止,似乎已经解决了。

J
Justin Cave

我相信答案是甲骨文非常非常古老。

早在 SQL 标准出现之前,Oracle 就做出了设计决定,即 VARCHAR/VARCHAR2 列中的空字符串为 NULL,并且只有一种 NULL 含义(有关系理论家会区分在从未被提示的数据、存在答案但用户不知道的数据、没有答案的数据等之间,所有这些都构成了NULL的某种意义。

当 SQL 标准出现并同意 NULL 和空字符串是不同的实体时,已经有 Oracle 用户的代码假定两者是等价的。因此,Oracle 基本上只能选择破坏现有代码、违反 SQL 标准或引入某种初始化参数来改变潜在大量查询的功能。违反 SQL 标准 (IMHO) 是这三个选项中破坏性最小的。

Oracle 保留了 VARCHAR 数据类型在未来版本中更改以符合 SQL 标准的可能性(这就是为什么每个人都在 Oracle 中使用 VARCHAR2,因为该数据类型的行为保证在未来保持不变) .


B
Brian

Tom Kyte 甲骨文副总裁:

零长度 varchar 被视为 NULL。 '' 不被视为 NULL。 '' 分配给 char(1) 时变为 ' ' (char 类型是空白填充字符串)。 '' 分配给 varchar2(1) 时变为 '',这是一个零长度字符串,而零长度字符串在 Oracle 中为 NULL(它不是长 '')


哇,汤姆很狡猾。鉴于这些问题与 SQL92 的严重分歧有关,您会认为他对此不会那么有力……尽管他可能已经厌倦了回答。
关于汤姆的最好的事情是你得到一个明确的答案,它准确地说明了他的想法。寻找人们在 Ask Tom 上使用文字发言的一些评论
但是如果将第二行更改为 '' 并不总是被视为 NULL 会更准确。
@ypercube 通过更改汤姆实际使用的单词,引用并没有变得更精确。如果您认为汤姆的措辞令人困惑,嗯。也许。我认为他准确。当 '' 隐式 转换为 VARCHAR2、such as cast('' as char(1)) is null which is... surprisingly TRUE 时,会出现最令人困惑的情况
@sehe 让我感到困惑的是 select 1 from dual where ('' is null)
W
Walter Mitty

Oracle 文档提醒开发人员注意这个问题,至少可以追溯到版本 7。

Oracle 选择用“不可能值”技术来表示 NULLS。例如,数字位置中的 NULL 将存储为“负零”,这是一个不可能的值。计算产生的任何负零都将在存储之前转换为正零。

Oracle 还错误地选择将长度为零的 VARCHAR 字符串(空字符串)视为不可能的值,并且是表示 NULL 的合适选择。事实证明,空字符串远非不可能的值。甚至是字符串拼接操作下的身份!

Oracle 文档警告数据库设计人员和开发人员,Oracle 的某些未来版本可能会破坏空字符串和 NULL 之间的这种关联,并破坏任何依赖于该关联的代码。

除了不可能的值之外,还有一些技术可以标记 NULLS,但 Oracle 没有使用它们。

(我在上面使用“位置”这个词来表示行和列的交集。)


Oracle 文档警告数据库设计人员和开发人员,Oracle 的某些未来版本可能会破坏空字符串和 NULL 之间的这种关联,并破坏任何依赖于该关联的代码——您能否提供此声明的参考?
u
user67897

如果您像早期开发人员可能会做的那样考虑 Oracle,我怀疑这会更有意义 - 作为数据输入系统的美化后端。数据库中的每个字段都对应于数据输入操作员在其屏幕上看到的表单中的字段。如果操作员没有在字段中输入任何内容,无论是“生日”还是“地址”,那么该字段的数据就是“未知”。操作员无法指示某人的地址实际上是一个空字符串,而且这实际上没有多大意义。


仅当您假设数据输入系统中的每个字段都是强制性的时,这才有意义。对非必填字段(例如“狗的名字”)的非回答是有效的,因此空字符串仍然具有与 NULL 不同的用途。即使有了这个假设,我怀疑早期的开发人员是否认为 Oracle 是“数据输入系统的美化后端”,所以我不确定这个答案是否有意义。
S
Sorter

According to official 11g docs

Oracle 数据库当前将长度为零的字符值视为空值。但是,在未来的版本中,这可能不会继续存在,Oracle 建议您不要将空字符串视为与 null 相同。

可能的原因

val IS NOT NULL 比 val != '' 更具可读性 无需检查两个条件 val != '' 和 val IS NOT NULL


在完全符合 ANSI 的数据库中,您不必检查这两个条件。 val <> '' 已排除 NULL。也许您的意思是 val = '' OR val IS NULL。但是不比较为 NULL 的空字符串是有用的
我同意比较部分。
A
Alex Kreutznaer

空字符串与 NULL 相同,只是因为与两者(空字符串和 null)不同的情况相比,它是“较小的邪恶”。

在 NULL 和空字符串不相同的语言中,必须始终检查这两个条件。


只需在您的列上设置 not null 约束并仅检查空字符串。
检查这两个条件很简单:WHERE Field <> '' 仅当字段不为 NULL 且不为空时才返回 true,在具有空字符串的 ANSI 行为的数据库上。
通过使它们相同,您会遇到唯一性问题,因为 NULL !== NULL'' === '',所以我认为这不是较小的邪恶。它增加了混乱。
z
zloctb

书中的例子

   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;

e
erikkallen

因为不将其视为 NULL 也不是特别有用。

如果您在 Oracle 上在这方面犯了错误,您通常会立即注意到。但是,在 SQL Server 中,它似乎可以工作,并且仅当有人输入空字符串而不是 NULL 时才会出现问题(可能来自 .net 客户端库,其中 null 与“”不同,但您通常将它们视为相同)。

我并不是说 Oracle 是对的,但在我看来,这两种方式都差不多一样糟糕。


调试起来容易得多。此外,如果您在屏幕上看到一个空单元格或输入,您就知道数据库中的数据为空。在 ''<>NULL 的其他数据库中,您无法“查看”数据是 null 还是 '',这会导致非常隐秘的错误。 ''=null 这是最明智的选择,即使它不是标准的。
“在其他 ''<>NULL 的数据库中,您无法“看到”数据是 null 还是 ''” => 通常,DB 工具显示 NULL 与空字符串不同。实际上,即使是 Oracle SQL Developer 也将 NULL 显示为“(null)”。我想这是为了区分 NULL 和空白,但它与 NULL 和空字符串之间的区别无关。
C
Cade Roux

事实上,我在处理 Oracle 时遇到了困难,包括无效的日期时间值(不能打印、转换或任何东西,只能用 DUMP() 函数查看),这些值被允许插入数据库,显然是通过一些错误客户端作为二进制列的版本!保护数据库完整性就这么多!

Oracle 处理 NULL 链接:

http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/

http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html


无效的数据时间值?不确定那是什么意思。您是否已将其作为问题发布在这里?
问题早于 stackoverflow - 我没有从 Oracle 论坛获得有用的信息,我创建了一个解决方法 - 我将跟踪我的笔记并在此处发布。
将详细信息作为问题发布在这里。
y
ypercubeᵀᴹ

首先,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,这是完全错误的。

我不明白他们为什么决定开始同等对待这两个不同的“价值观”。它们意味着不同的东西,程序员应该有能力以不同的方式对它们采取行动。他们改变了他们的方法的事实告诉我,他们真的不知道应该如何对待这些价值观。


区分“空字符串”和空值所需的引用。在除 Oracle 之外的任何数据库中,VARCHAR 字段可以有值(零个或多个字符)或无值 (NULL),句号。
从 2011 年开始的“五六年前”将落在 10g 时间范围内(2003 年发布 10.1,2005 年发布 10.2)。 10g 绝对没有在 null 的处理上引入任何全局更改,并且 NULL 和 null 值字符串之间从来没有任何区别,这样的区别是没有意义的。恐怕这个答案完全是幻想。