SQL和逻辑运算符以及空检查

Poi*_*nty 10 sql sql-server postgresql null

多年来我使用SQL Server时,我有一个模糊的,可能是货物崇拜的内存,当你有一个可能为空的列时,编写"WHERE"子句谓词就不安全了:

 ... WHERE the_column IS NULL OR the_column < 10 ...
Run Code Online (Sandbox Code Playgroud)

它与SQL规则没有规定短路这一事实有关(事实上,这可能是出于查询优化的原因,这可能是一个坏主意),因此可以评估"<"比较(或其他)即使列值为null.现在,确切地说,为什么这是一件可怕的事情,我不知道,但我记得有些文件严格警告总是将其编码为"CASE"条款:

 ... WHERE 1 = CASE WHEN the_column IS NULL THEN 1 WHEN the_column < 10 THEN 1 ELSE 0 END ...
Run Code Online (Sandbox Code Playgroud)

(愚蠢的"1 ="部分是因为SQL Server没有/没有一流的布尔值,或者至少我认为它没有.)

所以我的问题是:

  1. 对于SQL Server(或者可能是反向修改SQL Server 2000或2005)来说这是真的吗?或者我只是疯了吗?
  2. 如果是这样,同样的警告是否适用于PostgreSQL?(8.4如果重要)
  3. 究竟是什么问题?它与索引的工作原理有什么关系吗?

我在SQL方面的基础非常薄弱.

mu *_*ort 11

我不知道SQL Server,所以我不能说.

鉴于表达a L b一些逻辑运算L,也不能保证a会之前或之后进行评估b,甚至两者ab进行评估:

表达评估规则

子表达式的评估顺序没有定义.特别是,操作员或功能的输入不一定是从左到右或以任何其他固定顺序进行评估.

此外,如果表达式的结果可以通过仅评估它的某些部分来确定,则可能根本不评估其他子表达式.
[...]
请注意,这与某些编程语言中的布尔运算符的从左到右"短路"不同.

因此,使用具有副作用的函数作为复杂表达式的一部分是不明智的.依赖副作用或评估顺序WHEREHAVING条款尤其危险,因为这些条款作为制定执行计划的一部分进行了广泛的重新处理.

至于形式的表达:

the_column IS NULL OR the_column < 10
Run Code Online (Sandbox Code Playgroud)

而言,也没什么可说,因为担心NULL < nNULL所有n,甚至NULL < NULL计算结果为NULL; 而且,NULL事实并非如此

null is null or null < 10
Run Code Online (Sandbox Code Playgroud)

只是一种复杂的说法true or null,true无论首先评估哪个子表达式.

整个"使用案例"对我来说听起来就像是货物崇拜的SQL.然而,像大多数货物崇拜一样,货物下面埋藏着一个真相; 在我从PostgreSQL手册中摘录的第一部分之下,你会发现:

当强制评估顺序必不可少时,CASE可以使用构造(参见第9.16节).例如,这是一种不值得信任的方法,试图避免在一个WHERE子句中被零除:

SELECT ... WHERE x > 0 AND y/x > 1.5;
Run Code Online (Sandbox Code Playgroud)

但这是安全的:

SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Run Code Online (Sandbox Code Playgroud)

所以,如果你需要警惕,这将引发异常或有其他副作用的情况,那么你应该使用一个CASE作为控制评价的顺序CASE为了评估:

每个条件都是一个返回boolean结果的表达式.如果条件的结果为真,所述的值CASE表达是结果下面的条件,和所述的其余部分CASE不被处理的表达.如果条件的结果不成立,则以相同的方式检查任何后续的WHEN子句.

所以这个:

case when A then Ra
     when B then Rb
     when C then Rc
     ...
Run Code Online (Sandbox Code Playgroud)

A保证在之前B,B之前C等进行评估,并且只要其中一个条件评估为真值,评估就会停止.

总之,CASE短路既AND不会也不会OR短路,因此您只需要CASE在需要防止副作用时使用.