SQL逻辑运算符优先级:And和Or

228

以下两个语句等价吗?

SELECT [...]
FROM [...]
WHERE some_col in (1,2,3,4,5) AND some_other_expr

并且

SELECT [...]
FROM [...]
WHERE some_col in (1,2,3) or some_col in (4,5) AND some_other_expr

有没有一种真值表可以用来验证这个?


7
尝试:T T F. (T或T)和F. T或(T和F). 代码的读者应该清楚地看到代码作者的意图。而作者需要确保机器正在执行他想要的操作。括号对齐三者:读者、作者和机器。 :) - Assad Ebrahim
5个回答

374

And的优先级高于Or,所以即使a <=> a1 Or a2

Where a And b 

不同于

Where a1 Or a2 And b,

因为这将被执行为

Where a1 Or (a2 And b)

你想要的是使它们相同,需要做的是以下操作(使用括号来覆盖优先规则):

 Where (a1 Or a2) And b

这里有一个示例来说明:
Declare @x tinyInt = 1
Declare @y tinyInt = 0
Declare @z tinyInt = 0

Select Case When @x=1 OR @y=1 And @z=1 Then 'T' Else 'F' End -- outputs T
Select Case When (@x=1 OR @y=1) And @z=1 Then 'T' Else 'F' End -- outputs F

对于喜欢查阅参考资料的人(按字母顺序排列):


51
即使括号并非必需,使用括号是良好的编程习惯。几乎没有程序员(如果有的话)知道所有可用操作符的优先级。 - Trismegistos
1
@Trismegistos 希望不是这样的...不应该是这样的,但我猜你是对的。 - Charles Bretana
1
这个 AND 然后 OR 的优先级是 SQL 标准的一部分吗? - Jaime Hablutzel
我在MySQL中尝试了这个:X或Y且Z,它的运行结果是(X或Y)且Z - Abdul Rehman
4
@Bsienn,不确定您做了什么,但那与标准SQL和MySQL文档不一致...请再仔细尝试一次...尝试这个:declare @x tinyInt = 1 declare @y tinyInt = 0 declare @z tinyInt = 0 select case when @x=1 or @y=1 and @z=1 then'T' else 'F' end select case when (@x=1 or @y=1) and @z=1 then'T' else 'F' end - Charles Bretana
显示剩余3条评论

43

我再补充两点:

  • "IN" 本质上就是括号内多个 OR 连接的结果
  • 在我所知道的所有语言中,AND 的优先级高于 OR

因此这两个表达式根本不相等。

WHERE some_col in (1,2,3,4,5) AND some_other_expr
--to the optimiser is this
WHERE
     (
     some_col = 1 OR
     some_col = 2 OR 
     some_col = 3 OR 
     some_col = 4 OR 
     some_col = 5
     )
     AND
     some_other_expr

因此,当您拆分IN子句时,会拆分串行OR,并更改优先级。


gbn ORACLE SQL 中是否存在结合性?如果是,那么我在哪里可以获取所有运算符的结合性呢? - Asif Mushtaq
3
尽管很遗憾,但在ruby中AND没有优先于OR!更糟糕的是,&&比||有优先级!这就是我不喜欢ruby的原因之一——它总是让我感到最惊讶。 2.2.1 :007 > true or true and false => false 2.2.1 :008 > true || true && false => true - Alex L

27
  1. 算术运算符
  2. 连接运算符
  3. 比较条件
  4. IS [NOT] NULL、LIKE、[NOT] IN
  5. [NOT] BETWEEN
  6. 不等于
  7. 逻辑非条件
  8. 逻辑与条件
  9. 逻辑或条件

您可以使用括号来覆盖优先规则。


10

显示一个三变量布尔表达式的真值表的查询:

;WITH cteData AS
(SELECT 0 AS A, 0 AS B, 0 AS C
UNION ALL SELECT 0,0,1
UNION ALL SELECT 0,1,0
UNION ALL SELECT 0,1,1
UNION ALL SELECT 1,0,0
UNION ALL SELECT 1,0,1
UNION ALL SELECT 1,1,0
UNION ALL SELECT 1,1,1
)
SELECT cteData.*,
    CASE WHEN

(A=1) OR (B=1) AND (C=1)

    THEN 'True' ELSE 'False' END AS Result
FROM cteData

(A=1) OR (B=1) AND (C=1) 的结果为:

A   B   C   Result
0   0   0   False
0   0   1   False
0   1   0   False
0   1   1   True
1   0   0   True
1   0   1   True
1   1   0   True
1   1   1   True

(A=1) OR ((B=1) AND (C=1))的结果与((A=1) OR (B=1)) AND (C=1)相同。

A   B   C   Result
0   0   0   False
0   0   1   False
0   1   0   False
0   1   1   True
1   0   0   False
1   0   1   True
1   1   0   False
1   1   1   True

2
这是使用布尔值的“三变量真值表”的一种变体。
WITH truth_values AS
  (SELECT FALSE AS A,        
          FALSE AS B,
          FALSE AS C
   UNION ALL SELECT FALSE,
                    FALSE,
                    TRUE
   UNION ALL SELECT FALSE,
                    TRUE,
                    FALSE
   UNION ALL SELECT FALSE,
                    TRUE,
                    TRUE
   UNION ALL SELECT TRUE,
                    FALSE,
                    FALSE
   UNION ALL SELECT TRUE,
                    FALSE,
                    TRUE
   UNION ALL SELECT TRUE,
                    TRUE,
                    FALSE
   UNION ALL SELECT TRUE,
                    TRUE,
                    TRUE),
     logics AS
  (SELECT truth_values.*,
          a
   OR b
   AND c AS no_parens, (a
                        OR b)
   AND c AS or_parens
   FROM truth_values)
SELECT *,
       no_parens != or_parens AS parens_made_a_difference
FROM logics
ORDER BY a,
         b,
         c

以下是结果:

# A B C no_parens or_parens parens_made_a_difference
1
2
3
4
5
6
7
8

如果 'parens_made_a_difference' 为 true,则说明括号有影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接