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

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

我有一个表t,其中(仅)两列xy均为int类型。我怀疑这无关紧要,但是为了确定起见,我们说(x,y)t的主键。该表包含(仅)以下值:

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

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

例如,以下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?是否需要缓冲?

甚至有更糟糕的情况,请仔细考虑这一点,根据语义的不同,它们可能会破坏 bool(boolean) 型短路或需要四值 bool(boolean) 逻辑限制:
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

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

我希望在这里提供指导,因为我似乎找不到规范的相关部分。

最佳答案

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

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

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子句(可耻!)。在计算列之前,应始终应用where子句或predicate

考虑一下此查询:
select x, y, x/y as quot from t where x%2 = 0

如果我们有一条记录(3,0),它将应用where条件,并检查3 % 2 = 0是否。它不会,因此它不会在列计算中包括该记录,并将其留在原处。

10-06 10:22
查看更多