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

16

En la WHEREcláusula de una consulta SQL, esperaría que estas dos condiciones tengan el mismo comportamiento:

NOT (a=1 AND b=1)

vs

a<>1 AND b<>1

La primera condición se comporta como se esperaba, y aunque presento la segunda condición para hacer lo mismo, no lo hace.

Esto es algo muy básico, pero avergonzado no puedo ver lo que estoy haciendo mal.

jon
fuente
¿Puedes publicar datos de ejemplo y resultados esperados versus resultados reales?
Gareth Lyons
66
Como señaló Lenard en su respuesta, este es un ejemplo de las reglas de De Morgan: no (A y B) = (no A) o (no B) , no (A o B) = (no A) y (no B) . Tenga cuidado con los valores NULL.
Barranka
2
Solo piense en inglés. Su primera pregunta es "No es el caso de que yo sea el Rey de Francia y también el humano", absolutamente cierto. Su segundo es "No soy el Rey de Francia ni el ser humano", eminentemente falso.
Patrick Stevens
3
Esto entra en conflicto con la "ley de De Morgan". El equivalente sería a <> 1 OR b<>1.
Willem Van Onsem

Respuestas:

46

No son equivalentes.

NOT (a=1 AND b=1)

es equivalente a:

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

Esta equivalencia se conoce como De Morgan's Law. Ver por ejemplo:

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

Una buena técnica para probar / refutar equivalencias para expresiones de álgebra booleana es usar un cte para los dominios y comparar las expresiones una al lado de la otra:

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

Editar: como DB2 no admite el tipo de datos booleano, amplié el ejemplo en:

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

La consulta reescrita se ve así:

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;

El resultado de la consulta es:

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)

Como se muestra, exp1 y exp2 son equivalentes.

Lennart
fuente
16
+1 solo por mencionar a De Morgan. Debería requerirse la lectura para cualquiera que esté haciendo algún tipo de programación / scripting.
Tonny
¿Pero qué hay de NULL?
dan04
@ dan04 Puede agregar NULL a la primera línea (se convierte with T(a) as ( values 0,1,NULL )y vuelve a ejecutar la consulta y verá lo que sucede. Los NULL definitivamente arrojan una llave en la mayoría de las reglas de equivalencia establecidas que aprendemos. La respuesta corta es a = NULL y a < > NULL producen NULL, por lo que caerán en el caso de lo contrario. Para leer más: ( stackoverflow.com/questions/1833949/… )
Brian J
No estoy seguro de por qué tuvo que modificar el primer ejemplo para DB2. Funciona como se muestra para mí. Estoy usando DB2 para i en lugar de DB2 LUW. El segundo ejemplo tiene algunos errores de sintaxis para DB2 para i.
jmarkmurphy
@jmarkmurphy, no conozco DB2 para mí, tal vez funcione allí. Para LUW, la expresión de caso se asigna a 0 o 1, por lo que debe cambiarse para incluir también nulo. Al hacerlo, la expresión de caso ya no es trivial (IMO), y las expresiones se vuelven difíciles de razonar.
Lennart
9

Tu primer ejemplo dice:

Devolver todas las filas excepto donde tanto a = 1 Y b = 1

Su segundo ejemplo dice:

Devolver todas las filas , excepto donde ya sea a = 1 O b = 1

Para la segunda consulta para devolver el mismo que el primero, debe cambiar su ANDa 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);

Esto devuelve los siguientes resultados

a   b
0   0
1   0
0   1
Mark Sinkinson
fuente
¿Podría describir por qué se a<>1 AND b<>1traduce como "a = 1 O b = 1"?
doub1ejack
1
@ doub1ejack, necesita una negación adicional en su segunda declaración para que sea equivalente a la primera: NOT ( a=1 OR b=1 ). Los lenguajes naturales desafortunados contienen ambigüedades que dificultan la traducción de fórmulas lógicas a lenguajes naturales y viceversa. Por ejemplo, ¿ neither a=1 nor b=1significa NOT ( a=1 OR b=1 )o (NOT a=1) OR (NOT b=1)?
Lennart
1
@ duda1ejack Lo opuesto a "el auto es rojo Y tiene cuatro puertas" es "O el auto no es rojo, O no tiene cuatro puertas". Si varias cosas tienen que ser verdaderas para que una declaración sea verdadera, entonces solo una de ellas tiene que ser falsa para que sea falsa.
hobbs