代码之家  ›  专栏  ›  技术社区  ›  Doug McClean

SQL标准中错误值的处理

  •  1
  • Doug McClean  · 技术社区  · 16 年前

    我有一个关于SQL标准的问题,我希望它是SQL language lawyer 可以帮助。

    某些表达方式不起作用。 62 / 0 例如。SQL标准规定了许多表达式以类似方式出错的方法。许多语言使用特殊的异常流控制来处理这些表达式,或者 bottom pSueDo值。

    我有一张桌子, t ,只有两列, x y 每种类型 int . 我怀疑这不相关,但为了明确起见,我们这么说吧 (x,y) 是的主键 T . 此表仅包含以下值:

    x    y
    7    2
    3    0
    4    1
    26   5
    31   0
    9    3
    

    SQL标准要求的行为 SELECT 在此表上操作的表达式可能涉及被零除?或者,如果不需要任何行为,则允许哪些行为?

    例如,以下select语句需要什么行为?

    简单的一个:

    SELECT x, y, x / y AS quot
    FROM t
    

    更难的一个:

    SELECT x, y, x / y AS quot
    FROM t
    WHERE y != 0
    

    更难的是:

    SELECT x, y, x / y AS quot
    FROM t
    WHERE x % 2 = 0
    

    是否允许一个实现(例如,未能在更复杂的查询版本上实现限制可以在扩展内移动)生成一个除法为零的错误来响应该查询,因为,假设它试图除法 3 通过 0 在执行限制并意识到这一点之前,作为扩展的一部分 3 % 2 = 1 ?例如,如果扩展在一个小表上,那么这可能变得很重要,但是结果——当与一个大表联接并在大表中的数据基础上进行限制时——最终限制了所有需要被零除的行。

    如果t有数百万行,并且最后一个查询是由表扫描执行的,那么当遇到一个偶数值x(零值y)时,是否允许一个实现返回前几百万个结果,然后在接近结尾处发现除数为零?需要缓冲吗?

    更糟糕的情况是,考虑到这一点,根据语义,这可能会破坏布尔短路,或在限制条件下需要四值布尔逻辑:

    SELECT x, y
    FROM t
    WHERE ((x / y) >= 2) AND ((x % 2) = 0)
    

    如果桌子很大,这个短路问题会变得非常疯狂。假设表有一百万行,其中一行有一个0除数。标准中的语义是:

    SELECT CASE 
           WHEN EXISTS 
                (
                    SELECT x, y, x / y AS quot
                    FROM t
                )
           THEN 1
           ELSE 0
           END AS what_is_my_value
    

    似乎这个值应该是一个错误,因为它依赖于一个错误结果的空性或非空性,但是采用这些语义似乎会禁止优化器在这里短路表扫描。此存在性查询是否需要证明存在一个非底部行,或者也需要证明不存在底部行?

    我很感谢这里的指导,因为我似乎找不到规范的相关部分。

    1 回复  |  直到 16 年前
        1
  •  1
  •   Eric    16 年前

    我使用过的所有SQL实现都将除法0视为即时的 NaN #INF . 部门应该由前端来处理,而不是由实现本身来处理。查询不应该是最底层的,但是结果集需要返回 在这种情况下。因此,它与结果集同时返回,并且不会向用户显示任何特殊警告或消息。

    无论如何,要正确处理此问题,请使用以下查询:

    select
       x, y, 
       case y 
           when 0 then null 
           else x / y 
       end as quot
    from
       t
    

    要回答最后一个问题,请使用以下声明:

    SELECT x, y, x / y AS quot
    FROM t
    

    将返回此:

    x    y   quot
    7    2    3.5
    3    0    NaN
    4    1      4
    26   5    5.2
    31   0    NaN
    9    3      3
    

    所以,你的 exists 会找到所有的行 t 不管他们的商是多少。

    另外,我又读了一遍你的问题,意识到我没有讨论过 where 条款(羞愧!). The 哪里 子句,或 predicate 应该 总是 在计算列之前应用。

    想想这个问题:

    select x, y, x/y as quot from t where x%2 = 0
    

    如果我们有记录(3,0),它适用于 哪里 条件,并检查 3 % 2 = 0 . 它没有,所以它没有将该记录包括在列计算中,并将其保留在正确的位置。