【问题标题】:Is this implementation SQL-92 conformant?这个实现是否符合 SQL-92?
【发布时间】:2010-10-02 12:36:50
【问题描述】:

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

【问题讨论】:

    标签: sql oracle plsql


    【解决方案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 一样;这实际上是一个未定义的操作。

    【讨论】:

    • +1 链接。但是,正如我所阅读的,该标准明确指出将空值与任何内容连接的结果应该是空值。
    • @DCookie:啊,我以为你在问 COALESCE 的实现是否符合标准。但是,我同意,他们的 CONCATENATION 实现不符合标准,如果它为此返回非 NULL。
    • 抱歉没有把它拼出来,我想我从我给出的例子中假设我指的是连接操作:-(
    • 不,无论如何这可能是有道理的,我确定我只是浏览得太快了:)
    【解决方案2】:
    SQL>  select 'something'||null from dual;
    
    'SOMETHIN
    ---------
    something
    

    字符串与空值的连接不会产生空值。我认为这是正常的行为,我已经习惯了。不知道还能说什么。

    【讨论】:

    • 仅仅因为 Oracle 以这种方式实现它并不能使其正确。
    • 当它按照手册中的说明工作时是正确的。
    • 例如,Oracle 将空字符串等同于 NULL 被许多人认为是不正确的。
    • 我在问它是否符合 SQL 标准。抱歉,如果不清楚。
    • 是否符合SQL标准我不知道。
    【解决方案3】:

    @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 实施是否符合标准。但是,我同意,他们的 CONCATENATION 实现不符合标准,如果它为此返回非 NULL。
    • 是的,我的问题不是很清楚。我很抱歉。至少知道我的意思;-)
    【解决方案4】:

    根据 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)
    

    【讨论】:

      【解决方案5】:

      不,Oracle 对 null 的处理是特殊的,与其他所有人的不同,并且与 ANSI 标准不一致。然而,在 Oracle 的辩护中,它可能早在 ANSI 标准出现之前就已经确定并致力于这种处理方式!

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

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

      LENGTH('abc') + LENGTH('') IS NULL
      
      LENGTH('abc' || '') = 3
      

      在我看来这违反了基本的数学原理。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-10
        • 2014-08-19
        • 2014-06-09
        • 2012-06-06
        相关资源
        最近更新 更多