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


16

Nella WHEREclausola di una query SQL mi aspetto che queste due condizioni abbiano lo stesso comportamento:

NOT (a=1 AND b=1)

vs

a<>1 AND b<>1

La prima condizione si comporta come previsto, e anche se epico la seconda condizione per fare la stessa cosa, non lo fa.

Questa è roba molto semplice, ma vergognosamente non riesco a vedere cosa sto facendo di sbagliato.


Puoi pubblicare dati di esempio e risultati previsti rispetto ai risultati effettivi?
— Gareth Lyons,

6
Come notato da Lenard nella sua risposta, questo è un esempio delle regole di De Morgan: non (A e B) = (non A) o (non B) , non (A o B) = (non A) e (non B) . Fai attenzione ai valori NULL.
— Barranka

2
Pensaci in inglese. Il tuo primo è "Non è il caso che io sia sia il re di Francia che anche umano" - eminentemente vero. Il tuo secondo è "Non sono né il re di Francia né umano" - eminentemente falso.
— Patrick Stevens,

3
Ciò è in conflitto con la "legge di De Morgan". L'equivalente sarebbe a <> 1 OR b<>1.
— Willem Van Onsem,

Risposte:


46

Non sono equivalenti.

NOT (a=1 AND b=1)

è equivalente a:

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

Questa equivalenza è nota come De Morgan's Law. Vedi ad esempio:

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

Una buona tecnica per dimostrare / smentire le equivalenze per le espressioni algebriche booleane è quella di usare un cte per i domini e confrontare le espressioni fianco a fianco:

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

Modifica: poiché DB2 non supporta il tipo di dati booleano ho ampliato l'esempio in:

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

La query riscritta assomiglia a:

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;

Il risultato della query è:

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)

Come mostrato exp1 ed exp2 sono equivalenti.


16
+1 solo per menzionare De Morgan. Dovrebbe essere richiesta la lettura per chiunque faccia qualsiasi forma di programmazione / scripting.
— Tonny,

Ma che dire di NULL?
— dan04,

@ dan04 Puoi aggiungere NULL alla prima riga (diventa with T(a) as ( values 0,1,NULL )ed esegui nuovamente la query e vedrai cosa succede. I NULL lanciano sicuramente una chiave inglese nella maggior parte delle regole di equivalenza impostate che apprendiamo. La risposta breve è a = NULL e a < > NULL entrambi danno NULL, quindi cadranno nell'altro caso Per ulteriori letture: ( stackoverflow.com/questions/1833949/… )
— Brian J

Non sono sicuro del motivo per cui è stato necessario modificare il primo esempio per DB2. Funziona come mostrato per me. Sto usando DB2 per i anziché DB2 LUW. Il secondo esempio presenta alcuni errori di sintassi per DB2 per i.
— jmarkmurphy,

@jmarkmurphy, non conosco DB2 per me, forse funziona lì. Per LUW l'espressione case è associata a 0 o 1, quindi è necessario modificarla per includere anche null. In questo modo l'espressione del caso non è più banale (IMO) e le espressioni diventano difficili da ragionare.
— Lennart,

9

Il tuo primo esempio sta dicendo:

Restituisce tutte le righe tranne dove sia a = 1 AND b = 1

Il tuo secondo esempio sta dicendo:

Tutte le righe eccetto dove sia a = 1 OR b = 1

Affinché la seconda query restituisca la stessa della prima, è necessario modificare la propria ANDin unaOR

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

Questo restituisce i seguenti risultati

a   b
0   0
1   0
0   1

Potresti descrivere perché si a<>1 AND b<>1traduce in "o a = 1 OR b = 1"?
— doub1ejack,

1
@ doub1ejack, è necessario un ulteriore negazione nella tua seconda affermazione per renderlo equivalente con la prima: NOT ( a=1 OR b=1 ). Sfortunati linguaggi naturali contengono ambiguità che rendono difficile tradurre le formule logiche in linguaggi naturali e viceversa. Ad esempio, neither a=1 nor b=1significa NOT ( a=1 OR b=1 )o (NOT a=1) OR (NOT b=1)?
— Lennart,

1
@ doub1ejack Il contrario di "l'auto è rossa E ha quattro porte" è "O l'auto non è rossa, O non ha quattro porte". Se più cose devono essere vere per rendere vera un'affermazione, solo una di esse deve essere falsa per renderla falsa.
— Hobbs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.