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.