这个实现SQL-92是否符合要求?

时间:2009-01-20 18:25:48

标签: sql oracle plsql

另一个Tony Andrews中的

question举了一个例子:

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函数的一个聪明(如果不是有点模糊)的替代品。果然,它有效,如果任何参数不为null,则IF测试为真。我的问题:Oracle的上述串联操作SQL-92的实现是否符合要求?涉及NULL的表达式不应该计算为NULL吗?如果您不这么认为,那么为什么表达式1 + NULL计算为NULL?

5 个答案:

答案 0 :(得分:3)

不,Oracle对空值的处理是特殊的,与其他人不同,并且与ANSI标准不一致。然而,在甲骨文的辩护中,它可能已经确定并且在ANSI标准与之一致之前很久就致力于这种处理!

这一切都始于Oracle存储字符串后跟字符串数据的字符串。 NULL由字符计数零表示,没有后续字符串数据 - 这与空字符串('')完全相同。 Oracle根本没有办法区分它们。

这会导致一些古怪的行为,例如这种连接情况。 Oracle还有一个函数LENGTH来返回字符串的长度,但是这已经以相反的方式定义,因此LENGTH('')返回NULL而不是零。所以:

LENGTH('abc') + LENGTH('') IS NULL

LENGTH('abc' || '') = 3
在我看来,这违反了基本的数学原理。

当然,Oracle开发人员已经习惯了这一点,以至于我们中的许多人甚至看不到任何错误或奇怪的事情 - 事实上有些人会认为世界其他地方是错误的,并且空字符串和NULL 同样的事情!

答案 1 :(得分: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.

答案 2 :(得分:1)

COALESCE由SQL-92标准明确定义,以返回列表中的第一个非NULL值;所以根据定义,Oracle的实现行为正确。

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

也就是说,没有任何关于NULL的具体信息表明任何涉及NULL的操作必须为NULL。更确切的限制是NULL既不是假也不是0也不等于另一个NULL(例如,NULL == NULL是假的,因为一个NULL不等于另一个NULL)。但是,这并不意味着仍然存在逻辑上一致的使用NULL的方法,这些方法并不总是返回NULL。

编辑:所以NULL + 1是NULL,就像NaN + 1仍然是NaN一样;它实际上是一个未定义的操作。

答案 3 :(得分: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)

答案 4 :(得分:0)

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

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

使用null进行字符串连接不会导致null。我认为这是正常行为,我已经习惯了。不知道还能说些什么。