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


216

我知道它确实将“”视为NULL,但这并不能告诉我为什么会这样。据我了解的SQL规范,“”与NULL-是一个有效的数据,而另一个则表示缺少相同的信息。

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


9
随意猜测?无论如何,我认为这不会为您提供最大的答案
。– SCdF

1
我想不是,但是我不确定这个问题是否有确定性,所以我想我会把门打开。到目前为止,似乎已经解决了。
克里斯R


Answers:


216

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

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

到SQL标准出现并同意NULL并且空字符串是不同的实体时,已经有Oracle用户使用了假定两者相等的代码。因此,Oracle基本上可以选择破坏现有代码,违反SQL标准或引入某种初始化参数的选项,这些参数可能会更改潜在大量查询的功能。在这三个选项中,违反SQL标准(IMHO)的破坏最少。

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


60

Tom Kyte Oracle副总裁:

零长度的varchar被视为NULL。

''不被视为NULL。

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

''在分配给varchar2(1)时变为'',这是Oracle中的零长度字符串而零长度字符串为NULL(不长'')


17
哇,汤姆很。鉴于这些问题与SQL92的巨大差异有关,您可能会认为他对它的影响不那么大……尽管他可能不愿意回答。
克里斯·R

8
关于汤姆,最好的事情是您得到一个明确的答案,准确地说明了他的想法。寻找一些人们对使用的文本说话的意见向汤姆
李云飞

9
但是,如果第二行更改为”并不总是视为NULL
ypercubeᵀᴹ

2
@ypercube通过更改Tom实际使用的单词,报价不会变得更加精确。如果您认为汤姆的措辞令人困惑,嗯。也许。我认为他在现场。当''将其隐式转换为VARCHAR2时,会出现最令人困惑的情况,例如cast('' as char(1)) is null……令人惊讶的是
sehe 2013年

1
@sehe对我来说令人困惑的位是从对偶中选择1,其中(''为null)
马特·弗雷克(Matt freake

20

我怀疑如果您像以前的开发人员那样思考Oracle,将它作为数据输入系统的光荣后端,这在很大程度上会更有意义。数据库中的每个字段都对应一个数据输入操作员在其屏幕上看到的格式的字段。如果操作员未在字段中键入任何内容,无论是“生日”还是“地址”,则该字段的数据均为“未知”。操作员无法指出某人的地址确实是一个空字符串,无论如何这实际上没有多大意义。


5
仅当您假设数据输入系统中的每个字段都是必填字段时,这才有意义。对非必填字段的非回答(例如“狗的名字”)是有效的,因此空字符串仍然具有与NULL不同的用途。即使有了这个假设,我仍然怀疑早期的开发人员是否将Oracle视为“数据输入系统的光荣后端”,因此我不确定这个答案是否完全有意义。
Jared 2015年

19

Oracle文档警告开发人员注意此问题,至少可以追溯到版本7。

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

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

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

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

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


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


2

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

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


只需not null在列上设置约束,然后仅检查空字符串即可。
Egor Skriptunoff 2013年

6
检查这两个条件是很简单的:WHERE Field <> ''对于具有空字符串的ANSI行为的数据库,仅当字段不为NULL且不为空时,才返回true。

1

根据官方的11g文档

Oracle数据库当前将长度为零的字符值视为空值。但是,在将来的发行版中,情况可能不会继续如此,并且Oracle建议您不要将空字符串与null相同。

可能的原因

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

5
在完全符合ANSI的数据库中,您不必检查这两种情况。val <> ''已经排除NULL。也许你的意思是val = '' OR val IS NULL。但是不比较为NULL的空字符串很有用
ErikE

我同意比较部分。
Sorter

0

书中的例子

   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;

-1

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

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

我并不是说甲骨文是对的,但是在我看来,这两种方法几乎都同样糟糕。


2
调试起来要容易得多。另外,如果您在屏幕上看到一个空单元格或输入,则知道DB中的数据为空。在其他数据库中,“ <> NULL”中,您无法“查看”数据是否为null或,这会导致非常隐蔽的错误。''= null是最明智的选择,即使它不是标准的。
Lucio M. Tato

2
“在其他数据库中,如果<<> NULL,则不能“看到”数据是否为空或“”。实际上,即使Oracle SQL Developer也将NULL显示为“(null)”。我想这是为了将NULL与空白区分开来,但这与NULL和空字符串之间的区别无关。
Didier L

-6

事实上,我有什么,但困难与甲骨文打交道,包括无效的日期时间值(不能打印,转换或什么,只是看着与DUMP()函数),它们允许被插入到数据库中,显然是经过了一些越野车客户端版本作为二进制列!保护数据库完整性非常重要!

Oracle对NULL链接的处理:

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

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


1
无效的数据时间值?不确定那是什么意思。您是否已在此处发布此问题?

1
这个问题是在堆栈溢出之前发生的-我从Oracle论坛上没有得到有用的信息,并且创建了一种解决方法-我将跟踪我的笔记并在此处发布。
卡德·鲁

在此处发布详细信息作为问题。
卡德·鲁

-6

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

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

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

我不明白为什么他们决定开始将这两个不同的“值”相同地对待。它们意味着不同的事物,程序员应具有以不同方式对每种事物进行操作的能力。他们改变了方法论的事实告诉我,他们对如何对待这些价值观一无所知。


区分“空字符串”和NULL值所需的引用。在除Oracle之外的任何数据库中,一个VARCHAR字段可以有一个值(零个或多个字符)或没有值(NULL),句号。

从2011年开始的“五六年前”将落在10g的时间范围内(2003年发布的10.1,2005年发布的10.2)。10g绝对不会在处理null时引入任何全局更改,并且从未NULL与null值的字符串之间存在任何区别,而且这种区别是没有意义的。恐怕这个答案是一个完整的幻想。
威廉·罗伯逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.