NICHT (a = 1 UND b = 1) gegen (a <> 1 UND b <> 1)

16

In der WHEREKlausel einer SQL-Abfrage würde ich erwarten, dass diese beiden Bedingungen dasselbe Verhalten aufweisen:

NOT (a=1 AND b=1)

vs

a<>1 AND b<>1

Die erste Bedingung verhält sich wie erwartet, und während ich die zweite Bedingung für dasselbe erwarte, ist dies nicht der Fall.

Das ist sehr grundlegend, aber ich kann leider nicht sehen, was ich falsch mache.

jon
quelle
Können Sie Beispieldaten und erwartete Ergebnisse im Vergleich zu tatsächlichen Ergebnissen veröffentlichen?
Gareth Lyons
6
Wie Lenard in seiner Antwort bemerkte, ist dies ein Beispiel für De Morgan-Regeln: nicht (A und B) = (nicht A) oder (nicht B) , nicht (A oder B) = (nicht A) und (nicht B) . Seien Sie vorsichtig mit NULL-Werten.
Barranka
2
Denken Sie nur auf Englisch darüber nach. Ihre erste lautet: "Es ist nicht so, dass ich sowohl der König von Frankreich als auch ein Mensch bin." Ihr zweiter ist "Ich bin weder der König von Frankreich noch ein Mensch" - überaus falsch.
Patrick Stevens
3
Dies widerspricht dem "Gesetz von De Morgan". Das Äquivalent wäre a <> 1 OR b<>1.
Willem Van Onsem

Antworten:

46

Sie sind nicht gleichwertig.

NOT (a=1 AND b=1)

ist gleichbedeutend mit:

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

Diese Äquivalenz ist bekannt als De Morgan's Law. Siehe zum Beispiel:

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

Eine gute Technik, um Äquivalenzen für boolesche Algebra-Ausdrücke zu beweisen / zu widerlegen, besteht darin, ein cte für die Domänen zu verwenden und die Ausdrücke nebeneinander zu vergleichen:

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

Bearbeiten: Da DB2 den Booleschen Datentyp nicht unterstützt, habe ich das Beispiel um Folgendes erweitert:

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

Die umgeschriebene Abfrage sieht folgendermaßen aus:

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;

Das Ergebnis der Abfrage ist:

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)

Wie gezeigt sind exp1 und exp2 äquivalent.

Lennart
quelle
16
+1 nur um De Morgan zu erwähnen. Sollte für jeden, der irgendeine Form von Programmierung / Scripting ausführt, zum Lesen erforderlich sein.
Tonny
Aber was ist mit NULL?
Dan04
@ dan04 Sie können der ersten Zeile NULL hinzufügen (wird with T(a) as ( values 0,1,NULL )die Abfrage und führt sie erneut aus, und Sie werden sehen, was passiert. NULLs werfen definitiv einen Schraubenschlüssel in die meisten gesetzten Äquivalenzregeln, die wir kennen. Die kurze Antwort lautet a = NULL und a < > NULL beide ergeben NULL, daher fallen sie in den Fall else. Für weitere Informationen : ( stackoverflow.com/questions/1833949/… )
Brian J
Ich bin mir nicht sicher, warum Sie das erste Beispiel für DB2 ändern mussten. Es funktioniert wie bei mir gezeigt. Ich verwende DB2 für i anstelle von DB2 LUW. Das zweite Beispiel enthält einige Syntaxfehler für DB2 für i.
Jmarkmurphy
@jmarkmurphy, ich kenne DB2 für i nicht, vielleicht funktioniert es dort. Für LUW ist der case-Ausdruck entweder 0 oder 1 zugeordnet, sodass auch null hinzugefügt werden muss. Auf diese Weise ist der case-Ausdruck nicht mehr trivial (IMO) und die Ausdrücke sind schwer zu erklären.
Lennart
9

Ihr erstes Beispiel lautet:

Gibt alle Zeilen außer denen sowohl a = 1 und b = 1

Ihr zweites Beispiel lautet:

Gibt alle Zeilen außer denen entweder a = 1 OR b = 1

Damit die zweite Abfrage dieselbe wie die erste zurückgibt, sollten Sie Ihre ANDin eine ändernOR

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);

Dies gibt die folgenden Ergebnisse zurück

a   b
0   0
1   0
0   1
Mark Sinkinson
quelle
Können Sie beschreiben, warum a<>1 AND b<>1"entweder a = 1 ODER b = 1" bedeutet?
doub1ejack
1
@ doub1ejack, müssen Sie eine zusätzliche Negation in der zweiten Aussage es gleichbedeutend mit dem ersten machen: NOT ( a=1 OR b=1 ). Unglückliche natürliche Sprachen enthalten Mehrdeutigkeiten, die es schwierig machen, logische Formeln in natürliche Sprachen zu übersetzen und umgekehrt. Zum Beispiel ist neither a=1 nor b=1meine NOT ( a=1 OR b=1 )oder (NOT a=1) OR (NOT b=1)?
Lennart
1
@ doub1ejack Das Gegenteil von "Das Auto ist rot UND hat vier Türen" ist "Entweder ist das Auto nicht rot oder es hat keine vier Türen". Wenn mehrere Dinge wahr sein müssen, um eine Aussage wahr zu machen, muss nur eines falsch sein, um sie falsch zu machen.
Hobbs