这个实现符合SQL-92标准吗?

5

Tony Andrews在另一个问题中给出了以下示例:

IF p_c_courtesies_cd 
   || p_c_language_cd 
   || v_c_name 
   || v_c_firstname 
   || v_c_function 
   || p_c_phone 
   || p_c_mobile p_c_fax 
   || v_c_email is not null
THEN
     -- Do something
END IF;

作为 Oracle COALESCE 函数的一个聪明(如果不是有点晦涩)的替代方案。确实,它有效,如果任何参数不为空,IF 测试就会为 true。我的问题是:上述连接操作的 Oracle 实现是否符合 SQL-92 标准?一个涉及空值的表达式不应该被计算为空值吗?如果您不这样认为,那么为什么表达式 1 + NULL 应计算为空值?
5个回答

3
不,Oracle对null的处理方式很独特,与其他人不同,并且与ANSI标准不一致。然而,在辩护Oracle时,可能是因为早在有ANSI标准之前,它就确定并承诺了这种处理方式!
所有的一切都始于Oracle将字符串存储为字符计数后跟随字符串数据。一个空值被表示为零字符计数和没有后续字符串数据,这与一个空字符串('')完全相同。Oracle简单地没有区分它们的方法。
这导致一些奇怪的行为,例如这个连接情况。Oracle还有一个长度函数来返回字符串的长度,但是这个函数定义相反,所以LENGTH('')返回NULL而不是零。所以:
LENGTH('abc') + LENGTH('') IS NULL

LENGTH('abc' || '') = 3

这似乎违背了基本的数学原理。

当然,Oracle开发人员已经习惯了这种情况,以至于我们中的许多人甚至无法看出任何错误或奇怪之处 - 有些人实际上会争辩说空字符串和NULL相同的东西!


2

@Nezroy:感谢提供链接。然而,根据我阅读的标准,我认为它指出Oracle的实现实际上是错误的。第6.13节“通用规则”,2a条款:

     2) If <concatenation> is specified, then let S1 and S2 be the re-
        sult of the <character value expression> and <character factor>,
        respectively.

        Case:

        a) If either S1 or S2 is the null value, then the result of the
          <concatenation> is the null value.

我最初以为你是在问COALESCE的实现是否符合标准。然而,我同意,如果它返回非NULL值,他们的CONCATENATION实现就不符合标准。 - nezroy
是的,我的问题并不十分清晰。请原谅我。至少知道我想表达什么;-) - DCookie

1

COALESCE在SQL-92标准中明确定义为返回列表中第一个非NULL值;因此,按定义,Oracle实现的行为是正确的。

编辑:SQL-92规范;搜索COALESCE以查看其定义。

话虽如此,关于NULL并没有特定的规定说明任何涉及NULL的操作必须为NULL。更确切的限制是NULL既不是false也不是0,也不等于另一个NULL(例如,NULL == NULL是false,因为一个NULL不等于另一个NULL)。然而,这并不意味着不能有逻辑上一致的处理NULL的方式,这些方式不总是返回NULL。

编辑:因此,NULL + 1与NaN + 1相同,仍然是NaN;它实际上是一种未定义的操作。


+1 for the link。然而,根据我所读的标准,明确规定将 null 值与任何内容连接的结果应为 null。 - DCookie
@DCookie:啊,我以为你在问COALESCE实现是否符合标准。然而,我同意,如果它返回非NULL值,他们的CONCATENATION实现就不符合标准。 - nezroy
抱歉没有详细说明,我猜想从我给出的示例中可以看出我是在指拼接操作 :-( - DCookie
没关系,可能那个意思本来就很清楚,我肯定只是看得太快了 :) - nezroy

1

基于 DCookie 强调的 SQL-92 规范部分以及其他数据库的行为,我认为 Oracle 的连接运算符并未遵循标准。

Oracle (来自 tuinstoel 的回答):

SQL>  select 'something'||null from dual;

'SOMETHIN
---------
something

MSSQL:

SELECT 'something'+NULL;

NULL

PostgreSQL:

postgres=# \pset null '(null)'
Null display is "(null)".
postgres=# select 'something'||null as output;
 output
--------
 (null)
(1 row)

MySQL:

mysql> select concat('something',NULL) as output;
+--------+
| output |
+--------+
| NULL   |
+--------+
1 row in set (0.00 sec)

0
SQL>  select 'something'||null from dual;

'SOMETHIN
---------
something

字符串与null连接不会得到null。我认为这是正常行为,我已经习惯了。不知道还有什么可以说的。

仅仅因为Oracle是这样实现的并不意味着它就是正确的。 - DCookie
只有在手册中所述的方式下正常工作时,才能说某个东西是正确的。 - tuinstoel
举个例子,Oracle将空字符串等同于NULL被许多人认为是不正确的。 - DCookie
我是在询问它是否符合SQL标准。如果没有表达清楚,我很抱歉。 - DCookie
我不知道它是否符合SQL标准。 - tuinstoel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接