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

jon*_*jon 16 condition

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

NOT (a=1 AND b=1)
Run Code Online (Sandbox Code Playgroud)

对比

a<>1 AND b<>1
Run Code Online (Sandbox Code Playgroud)

第一个条件的行为符合预期,虽然我希望第二个条件做同样的事情,但事实并非如此。

这是非常基本的东西,但可耻的是我看不出我做错了什么。

Len*_*art 47

它们不是等价的。

NOT (a=1 AND b=1)
Run Code Online (Sandbox Code Playgroud)

相当于:

(NOT a=1 OR NOT b=1) <=> (a<>1 OR b<>1)
Run Code Online (Sandbox Code Playgroud)

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

https://en.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
Run Code Online (Sandbox Code Playgroud)

编辑:由于 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;
Run Code Online (Sandbox Code Playgroud)

查询的结果是:

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)
Run Code Online (Sandbox Code Playgroud)

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

  • +1 只是为了提到德摩根。任何从事任何形式的编程/脚本编写的人都应该阅读。 (16认同)

Mar*_*son 9

你的第一个例子是说:

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

你的第二个例子是说:

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

要使第二个查询返回与第一个相同的查询,您应该将您AND的更改为OR

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);
Run Code Online (Sandbox Code Playgroud)

这将返回以下结果

a   b
0   0
1   0
0   1
Run Code Online (Sandbox Code Playgroud)