SELECT *
FROM Table t
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key)
如果
@key IS NULL
求值为true
,那么是否会求解@key IS NOT NULL AND @key = t.Key
?如果不会,为什么?
如果会,是否有保障?这是ANSI SQL的一部分还是特定于数据库的?
如果是数据库特定的,是SQLServer?Oracle?MySQL?
SELECT *
FROM Table t
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key)
@key IS NULL
求值为true
,那么是否会求解@key IS NOT NULL AND @key = t.Key
?ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf
6.3.3.3 规则评估顺序
[...]
如果优先级不是由格式或括号确定的话,表达式的有效计算通常从左到右进行。然而,当操作数或运算符可能导致条件被触发,或者如果表达式的结果可以在不完全计算所有部分的情况下确定时,则实际上是否按照从左到右的顺序计算表达式取决于具体实现。
0 = 0 或 null
= true 或 null
= true
,无论是否短路,因为 null
在语义上等同于 unknown
,而在这个析取式中的 unknown
是 true
还是 false
并不重要,因为 true or false
是 true
,true or true
也是 true
。null or 0 = 0
也是 true
。 - allmhuran从上面可以看出,短路并不可用。
如果您需要它,我建议使用Case语句:
Where Case when Expr1 then Expr2 else Expr3 end = desiredResult
Expr1
总是被计算,但每行只有一个 Expr2
和 Expr3
会被计算。
我认为这是一种情况,即使它不短路,我也会这样写,原因有三。
对于MSSQL,它不是通过在显然的位置查看BOL来解决的,所以对我来说,这使它具有规范上的歧义。
因为至少我知道我的代码将会起作用。更重要的是,那些接替我的人也是如此,所以我不会让他们反复担心同样的问题。
我经常为多个DBMS产品编写代码,并且如果可以轻松地避开它们,就不想记住差异。
我不相信在 SQL Server(2005)中短路运算是可以保证的。SQL Server 会通过其优化算法来运行您的查询,该算法考虑了许多因素(索引、统计信息、表大小、资源等),以得出一个有效的执行计划。在此评估之后,您无法确保您的短路逻辑是可靠的。
我曾经遇到过同样的问题,我的研究并没有给我一个明确的答案。您可以编写一个小查询来验证它是否有效,但是当您的数据库负载增加、表变得更大,并且数据库中的内容被优化和更改时,您能确定结论仍然成立吗?我不能,因此我选择谨慎起见,在 WHERE 子句中使用 CASE 来确保短路。
您需要记住数据库的工作原理。给定一个参数化查询,数据库会根据该查询构建执行计划,而不考虑参数的值。无论实际提供的值是什么,每次运行查询时都会使用此查询。查询是否在某些值下短路对执行计划没有影响。
SELECT [blah]
FROM Emp
WHERE ((@EmpID = -1) OR (@EmpID = EmpID))
非常方便,但不完全确定它会给数据库引擎带来额外的工作量。
二进制布尔运算符是可交换的,这意味着:
a AND b == b AND a
a OR b == b OR a
a XOR b == b XOR a
因此,无法保证评估顺序。评估顺序将由查询优化器确定。
在具有对象的语言中,可能存在只能使用短路评估来评估布尔表达式的情况。您的示例代码结构经常在这些语言中使用(如C#,Delphi,VB)。例如:
if(someString == null | someString.Length == 0 )
printf("no text in someString");
这个C#示例会导致异常,如果someString == null
,因为它将被完全评估。在短路评估中,它每次都能正常工作。
SQL仅对标量变量(没有对象)进行操作,这些变量不能未初始化,因此无法编写无法评估的布尔表达式。如果您有一些NULL值,则任何比较都将返回false。
这意味着在SQL中,您无法编写根据使用短路或完全评估而不同评估的表达式。
如果SQL实现使用短路评估,它只能希望加快查询执行速度。
我不知道短路运算,但我会将其写成if-else语句。
if (@key is null)
begin
SELECT *
FROM Table t
end
else
begin
SELECT *
FROM Table t
WHERE t.Key=@key
end
此外,变量应始终位于等式的右侧。这使其可搜索。
SELECT (value IS NULL) OR (value IS NOT NULL AND value='something')
不会返回任何行。 - Ast DerekWHERE a = 1 AND b = 2
,对于数据库引擎来说,先查找所有 b = 2 的行,然后再过滤 a = 1 可能更有效率。但如果要求保证,则优化器将变得无用。 - Salman A