【问题标题】:Why does Oracle 9i treat an empty string as NULL?为什么 Oracle 9i 将空字符串视为 NULL?
【发布时间】:2010-09-17 05:43:42
【问题描述】:

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

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

【问题讨论】:

标签: sql oracle null string


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    Tom Kyte甲骨文副总裁:

    零长度的 varchar 被视为 空。

    '' 不被视为 NULL。

    '' 分配给 char(1) 时变为 ' ' (字符类型为空白填充 字符串)。

    '' 分配给 varchar2(1) 时 变成 '' 这是一个零长度 字符串和零长度字符串是 Oracle 中的 NULL(它不再是 '')

    【讨论】:

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

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

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

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

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

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

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

    【讨论】:

    • Oracle 文档警告数据库设计人员和开发人员,Oracle 的某些未来版本可能会破坏空字符串和 NULL 之间的这种关联,并破坏任何依赖于该关联的代码 – 可能请您为此声明提供参考?
    【解决方案4】:

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

    【讨论】:

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

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

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

    【讨论】:

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

    According to official 11g docs

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

    可能的原因

    1. val IS NOT NULLval != '' 更易读
    2. 无需同时检查两个条件val != '' and val IS NOT NULL

    【讨论】:

    • 在完全符合 ANSI 的数据库中,您不必同时检查这两个条件。 val <> '' 已排除 NULL。也许你的意思是val = '' OR val IS NULL。但是不比较为 NULL 的空字符串是有用的
    • 我同意比较部分。
    【解决方案7】:

    书中的例子

       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;
    

    【讨论】:

      【解决方案8】:

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

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

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

      【讨论】:

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

      确实,我在处理 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 论坛获得有用的信息,我创建了一个解决方法 - 我将跟踪我的笔记并在此处发布。
      • 在此处作为问题发布详细信息。
      【解决方案10】:

      首先,Oracle 并不总是将 null 和 null 字符串视为相同的。根据定义,空字符串是不包含字符的字符串。这与 null 完全不同。 NULL,顾名思义,就是没有数据。

      五六年前,Oracle 对 null 字符串的处理方式与 null 不同。虽然和 null 一样,null 字符串等于所有内容,但与所有内容不同(我认为 null 很好,但 null 字符串完全错误),至少 length(null string) 会返回 0,因为 null 字符串是零长度的字符串。

      目前在 Oracle 中,length(null) 返回 null,我猜是可以的,但是 length(null string) 也返回 null,这是完全错误的。

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

      【讨论】:

      • 区分“空字符串”和空值所需的引用。在除 Oracle 之外的任何数据库中,VARCHAR 字段可以有值(零个或多个字符)或无值 (NULL),句号。
      • 从 2011 年开始的“五六年前”将属于 10g 时间范围(2003 年发布 10.1,2005 年发布 10.2)。 10g 绝对没有在处理空值时引入任何全局变化,NULL 和空值字符串之间也从来没有任何区别,这样的区别是没有意义的。恐怕这个答案完全是幻想。
      猜你喜欢
      • 1970-01-01
      • 2020-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      相关资源
      最近更新 更多