不(a = 1 AND b = 1)vs(a <> 1 AND b <> 1)


16

WHERESQL查询的子句中,我希望这两个条件具有相同的行为:

NOT (a=1 AND b=1)

a<>1 AND b<>1

第一个条件的行为符合预期,而我建议第二个条件做相同的事情,但事实并非如此。

这是非常基本的内容,但令人遗憾的是,我看不到自己在做错什么。


您可以发布示例数据,预期结果与实际结果吗?
加雷斯·里昂斯

6
正如Lenard在他的回答中所指出的,这是De Morgan规则的一个示例:不是(A和B)=(不是A)或(不是B)不是(A或B)=(不是A)和(不是B)。注意NULL值。
Barranka

2
只是用英语考虑一下。您的第一个意思是“我既不是法国国王又是人类”。您的第二个词是“我既不是法国国王也不是人类国王”-极为错误。
帕特里克·史蒂文斯

3
这与“德摩根定律”相冲突。等效为a <> 1 OR b<>1
Willem Van Onsem

Answers:


46

它们不是等效的。

NOT (a=1 AND b=1)

等效于:

(NOT a=1 OR NOT b=1) <=> (a<>1 OR b<>1)

这种等价称为De Morgan's Law。参见例如:

https://zh.wikipedia.org/wiki/De_Morgan%27s_laws

证明/证明布尔代数表达式的等价性的一种不错的技术是对域使用cte,并比较表达式:

with T(a) as ( values 0,1 )
   , U(a,b) as (select t1.a, t2.a as b 
               from t as t1 
               cross join t as t2
) 
select a,b
    , case when not (a=1 and b=1) then 1 else 0 end
    , case when a<>1 and b<>1 then 1 else 0 end 
from U

A           B           3           4          
----------- ----------- ----------- -----------
          0           0           1           1
          0           1           1           0
          1           0           1           0
          1           1           0           0

编辑:由于DB2不支持布尔数据类型,所以我在以下位置扩展了示例:

http://sqlfiddle.com/#!15/25e1a/19

重写的查询如下所示:

with T(a) as ( values (0),(1),(null) )
   , U(a,b) as (select t1.a, t2.a as b 
                from t as t1 
                cross join t as t2
) 
select a,b
     , not (a=1 and b=1) as exp1 
     , a<>1 or b<>1 as exp2
from U;

查询的结果是:

a       b       exp1        exp2
--------------------------------
0       0       true        true
0       1       true        true
0       (null)  true        true
1       0       true        true
1       1       false       false
1       (null)  (null)      (null)
(null)  0       true        true
(null)  1       (null)      (null)
(null)  (null)  (null)      (null)

如图所示,exp1和exp2是等效的。


16
+1只是为了提起De Morgan。任何从事任何形式的编程/脚本工作的人都应阅读。
Tonny

但是NULL呢?
dan04年

@ dan04您可以将NULL添加到第一行(with T(a) as ( values 0,1,NULL )然后重新运行查询,您会看到会发生什么。NULL肯定会在我们学习的大多数设置的等效规则中引起麻烦。简短的答案是a = NULL和a < > NULL都将产生NULL,因此它们将落入else情况。进一步阅读:(stackoverflow.com/questions/1833949/…
Brian J

我不确定为什么您必须修改DB2的第一个示例。如我所显示的。我正在为我使用DB2,而不是DB2 LUW。第二个示例在DB2 for i中有一些语法错误。
jmarkmurphy

@jmarkmurphy,我不了解DB2,也许它在那里工作。对于LUW,case表达式映射为0或1,因此必须更改为也包含null。这样一来,case表达式就不再是琐碎的(IMO)了,因此很难对此进行推理。
Lennart

9

您的第一个示例说:

返回所有行除了其中两个 A = 1 AND B = 1

您的第二个示例说:

返回所有行除外,其中任一 A = 1 OR B = 1

为了使第二个查询返回与第一个相同的查询,您应该将其更改ANDOR

CREATE TABLE #Test (a BIT, b BIT);

INSERT INTO #Test
        ( a, b )
VALUES
        ( 0, 0 ),
        ( 1, 0 ),
        ( 0, 1 ),
        ( 1, 1 );

SELECT * FROM #Test AS t
WHERE NOT (a=1 AND b=1);

SELECT * FROM #Test AS t
WHERE (a <> 1 OR b <> 1);

这将返回以下结果

a   b
0   0
1   0
0   1

您能否描述为什么a<>1 AND b<>1转换为“ a = 1或b = 1”?
doub1ejack

1
@ doub1ejack,您需要在第二条语句中附加一个否定词,使其与第一条等效:NOT ( a=1 OR b=1 )。不幸的是,自然语言包含歧义,因此很难将逻辑公式转换为自然语言,反之亦然。例如,是neither a=1 nor b=1NOT ( a=1 OR b=1 )还是(NOT a=1) OR (NOT b=1)
Lennart

1
@ doub1ejack“汽车是红色的并且有四个门”的反面是“或者汽车不是红色的,或者它没有四个门。” 如果要使一个语句为真,则必须满足多个条件,那么只有一个条件必须为假才能使其成为错误。
hobbs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.