No es igual a <>! = Operador en NULL

271

¿Podría alguien explicar el siguiente comportamiento en SQL?

SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)
Maxim Gershkovich
fuente

Respuestas:

309

<>es el estándar SQL-92; !=es su equivalente Ambos evalúan los valores, lo que NULLno es: NULLes un marcador de posición para decir que existe la ausencia de un valor.

Es por eso que solo puede usar IS NULL/ IS NOT NULLcomo predicados para tales situaciones.

Este comportamiento no es específico de SQL Server. Todos los dialectos SQL que cumplen con los estándares funcionan de la misma manera.

Nota : para comparar si su valor no es nulo , use IS NOT NULL, mientras que para comparar con un valor no nulo , use <> 'YOUR_VALUE'. No puedo decir si mi valor es igual o no a NULL, pero puedo decir si mi valor es NULL o NOT NULL. Puedo comparar si mi valor es algo distinto de NULL.

Ponis OMG
fuente
44
En realidad, creo <>que está en la especificación 92, pero la mayoría de los proveedores admiten !=y / o se incluye en una especificación posterior como 99 o 03.
Thomas
2
@Thomas: Oracle no soportó !=hasta ~ 9i, según tengo entendido, lo que trajo mucha sintaxis ANSI-92. Mi creencia es que MySQL es similar, comenzando el soporte en 4.x.
OMG Ponies
Eso parecería sugerir que !=podría haberse incluido en una especificación posterior como alternativa a <>. No tengo en mis manos nuevas especificaciones, así que no puedo decir con certeza.
Thomas
2
¿Es el resultado de WHERE MyColumn != NULLo WHERE MyColumn = NULLdeterminista? O, en otras palabras, ¿se garantiza que siempre devuelva 0 filas, sin importar si MyColumnes anulable en la base de datos o no?
Slauma
11
También debe tenerse en cuenta que debido a que !=solo evalúa los valores, hacer algo como WHERE MyColumn != 'somevalue'esto no devolverá los registros NULL.
jsumrall
88

NULL no tiene valor, por lo que no se puede comparar con los operadores de valor escalar.

En otras palabras, ningún valor puede ser igual (o no igual a) NULL porque NULL no tiene valor.

Por lo tanto, SQL tiene predicados especiales IS NULL y IS NOT NULL para tratar con NULL.

Barry Brown
fuente
3
+1. Y, contrariamente a la declaración OP, esto no es "Microsoft SQL". La lógica trinaria se define en el Estándar SQL y MS en este punto se adhiere al estándar.
TomTom
66
No estaba sugiriendo que este es un comportamiento único de Microsoft. Simplemente decía que lo observé en Microsoft SQL Server.
Maxim Gershkovich
13
Fuera de interés, ¿hay alguna situación en la que este comportamiento (esperado) sea útil? ¡Simplemente me parece que 'a' != nullNO devolver un valor ( true/ 1) es contrario a la intuición y me atrapa de vez en cuando! Pensé que "algún valor comparado con ningún valor" siempre sería "no igual", pero tal vez solo soy yo.
DarthPablo
1
Creo que es interesante que la gente describa NULL como " sin valor ". Similar, entonces, a decir que el número 1 'tiene un valor' cuando en realidad es un valor. Pero NULL representa falta de valor ..
systemaddict
Como solución manual, normalmente podría SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'asignar una constante si es un valor NULL, siempre que proporcione un tipo de datos apropiado para el valor centinela x (en este caso, una cadena / char). Esta es la sintaxis de TSQL, pero Oracle y otros motores tienen características similares.
systemaddict
26

Tenga en cuenta que este comportamiento es el comportamiento predeterminado (ANSI).

Si tu:

 SET ANSI_NULLS OFF

http://msdn.microsoft.com/en-us/library/ms188048.aspx

Obtendrás resultados diferentes.

SET ANSI_NULLS OFF aparentemente se irá en el futuro ...

Cade Roux
fuente
8
+1 ... no lo suficientemente pronto. Ahora, ¿cuándo puedo obtener NULL "duplicados" en un índice? :(
Puede obtener NULL duplicados en un índice de SQL Server agregando una cláusula WHERE en un índice filtrado (por ejemplo create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/library/cc280372.aspx
Anthony Mills
3
Nota de los documentos: cuando SET ANSI_NULLSestá desactivado, los operadores de comparación Igual (=) y No igual a (<>) no siguen el estándar ISO. Una instrucción SELECT que utiliza WHERE column_name = NULLdevuelve las filas que tienen valores nulos en column_name. Una instrucción SELECT que utiliza WHERE column_name <> NULLdevuelve las filas que tienen valores no nulos en la columna. Además, una instrucción SELECT que usa WHERE column_name <> XYZ_valuedevuelve todas las filas que no son XYZ_value y que no son NULL. En mi humilde opinión, esta última declaración parece un poco extraña en su exclusión de nulos de los resultados!
DarthPablo
44
Nota importante del documento msdn : en una versión futura de SQL Server [más reciente que 2014], ANSI_NULLS siempre estará ENCENDIDO y cualquier aplicación que establezca explícitamente la opción en APAGADO generará un error. Evite usar esta función en nuevos trabajos de desarrollo y planee modificar las aplicaciones que actualmente usan esta función.
Otiel
7

En SQL, todo lo que evalúa / calcula con NULLresultados en DESCONOCIDO

Es por eso que SELECT * FROM MyTable WHERE MyColumn != NULLo SELECT * FROM MyTable WHERE MyColumn <> NULLte da 0 resultados.

Para proporcionar una comprobación de NULLvalores, se proporciona la función isNull.

Además, puede usar el ISoperador como lo hizo en la tercera consulta.

Espero que esto ayude.

Mahendra Liya
fuente
"En SQL, todo lo que evalúa / calcula con NULL da como resultado 'NULL'" - incorrecto. El resultado que quiere decir es DESCONOCIDO.
cuando el
@MahendraLiya, la función isNull no se proporciona para verificar NULLS, pero " Reemplaza NULL con el valor de reemplazo especificado ". Debe usar IS NULL o IS NOT NULL en lugar de ISNULL, que es una cosa diferente.
Ingeniero invertido
7

La única prueba para NULL es IS NULL o IS NOT NULL. Las pruebas de igualdad no tienen sentido porque, por definición, uno no sabe cuál es el valor.

Aquí hay un artículo de Wikipedia para leer:

https://en.wikipedia.org/wiki/Null_(SQL)

dkretz
fuente
6

Usamos

SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';

para devolver todas las filas donde MyColumn es NULL o todas las filas donde MyColumn es una cadena vacía. Para muchos "usuarios finales", el problema de NULL frente a cadena vacía es una distinción sin necesidad ni punto de confusión.

Jeff Mergler
fuente
5

Simplemente no veo la razón funcional y sin problemas para que los valores nulos no sean comparables con otros valores u otros valores nulos, porque podemos compararlo claramente y decir que son iguales o no en nuestro contexto. Es gracioso. Solo por algunas conclusiones lógicas y consistencia, necesitamos molestarnos constantemente con eso. No es funcional, hágalo más funcional y deje que los filósofos y los científicos concluyan si es consistente o no y si tiene "lógica universal". :) Alguien puede decir que es debido a índices o algo más, dudo que esas cosas no puedan hacerse para admitir valores nulos iguales. Es lo mismo que comparar dos vasos vacíos, uno es vidrio de vid y otro es vaso de cerveza, no estamos comparando los tipos de objetos sino los valores que contienen, lo mismo que se podría comparar int y varchar, con nulo ' s aún más fácil, no es nada y lo que dos nada tienen en común, son lo mismo, claramente comparables por mí y por todos los demás que escriben sql, porque constantemente estamos rompiendo esa lógica al compararlos de manera extraña debido a algunos estándares ANSI. ¿Por qué no utilizar la potencia de la computadora para hacerlo por nosotros? Dudo que esto desacelere las cosas si todo lo relacionado se construye teniendo esto en cuenta. "No es nulo, no es nada", no es manzana, es apfel, vamos ... Funcionalmente es tu amigo y también hay lógica aquí. Al final, lo único que importa es la funcionalidad y el uso de valores nulos de esa manera brinda más o menos funcionalidad y facilidad de uso. ¿Es más útil? porque constantemente estamos rompiendo esa lógica al compararlos de manera extraña debido a algunos estándares ANSI. ¿Por qué no utilizar la potencia de la computadora para hacerlo por nosotros? Dudo que esto desacelere las cosas si todo lo relacionado se construye teniendo esto en cuenta. "No es nulo, no es nada", no es manzana, es apfel, vamos ... Funcionalmente es tu amigo y también hay lógica aquí. Al final, lo único que importa es la funcionalidad y el uso de valores nulos de esa manera brinda más o menos funcionalidad y facilidad de uso. ¿Es más útil? porque constantemente estamos rompiendo esa lógica al compararlos de manera extraña debido a algunos estándares ANSI. ¿Por qué no utilizar la potencia de la computadora para hacerlo por nosotros? Dudo que esto desacelere las cosas si todo lo relacionado se construye teniendo esto en cuenta. "No es nulo, no es nada", no es manzana, es apfel, vamos ... Funcionalmente es tu amigo y también hay lógica aquí. Al final, lo único que importa es la funcionalidad y el uso de valores nulos de esa manera brinda más o menos funcionalidad y facilidad de uso. ¿Es más útil? s no apple es apfel, vamos ... Funcionalmente es tu amigo y también hay lógica aquí. Al final, lo único que importa es la funcionalidad y el uso de valores nulos de esa manera brinda más o menos funcionalidad y facilidad de uso. ¿Es más útil? s no apple es apfel, vamos ... Funcionalmente es tu amigo y también hay lógica aquí. Al final, lo único que importa es la funcionalidad y el uso de valores nulos de esa manera brinda más o menos funcionalidad y facilidad de uso. ¿Es más útil?

Considera este código:

SELECT CASE WHEN NOT (1 = null or (1 is null and null is null)) THEN 1 ELSE 0 end

¿Cuántos de ustedes saben qué devolverá este código? Con o sin NOT devuelve 0. Para mí eso no es funcional y es confuso. En c # todo es como debería ser, las operaciones de comparación devuelven valor, lógicamente esto también produce valor, porque si no fuera así, no hay nada que comparar (excepto. Nada :)). Simplemente "dijeron": cualquier cosa en comparación con nulo "devuelve" 0 y eso crea muchas soluciones y dolores de cabeza.

Este es el código que me trajo aquí:

where a != b OR (a is null and b IS not null) OR (a IS not null and b IS null)

Solo necesito comparar si dos campos (en donde) tienen valores diferentes, podría usar la función, pero ...

Hrvoje Batrnek
fuente
4

NULL No se puede comparar con ningún valor utilizando los operadores de comparación. NULL = NULL es falso. Nulo no es un valor. El operador IS está especialmente diseñado para manejar comparaciones NULL.

Vincent Ramdhanie
fuente
55
Siempre me han gustado las personas confusas cuando a veces uso null = nulldonde se podría usar 1=0en alguna consulta ad-hoc. Y si se quejan, lo cambio a null != null:)
SWeko
8
"NULL = NULL es falso" Eso no es así. NULL = NULL se evalúa como desconocido y no falso.
nvogel
@dportas es así, pero quise decir que en un condicional no se evaluará como verdadero.
Vincent Ramdhanie
@VincentRamdhanie ni como falso; de hecho, en postgres se evaluará como NULL
Pere
2

Antigua pregunta, pero la siguiente podría ofrecer más detalles.

nullno representa ningún valor o un valor desconocido. No especifica por qué no hay valor, lo que puede generar cierta ambigüedad.

Supongamos que ejecuta una consulta como esta:

SELECT *
FROM orders
WHERE delivered=ordered;

es decir, está buscando filas donde las fechas orderedy deliveredsean iguales.

¿Qué se puede esperar cuando una o ambas columnas son nulas?

Debido a que al menos una de las fechas es desconocida, no puede esperar decir que las 2 fechas son las mismas. Este también es el caso cuando ambas fechas son desconocidas: ¿cómo pueden ser las mismas si ni siquiera sabemos cuáles son?

Por esta razón, cualquier expresión que se trate nullcomo un valor debe fallar. En este caso, no coincidirá. Este también es el caso si intenta lo siguiente:

SELECT *
FROM orders
WHERE delivered<>ordered;

Nuevamente, ¿cómo podemos decir que dos valores no son iguales si no sabemos cuáles son?

SQL tiene una prueba específica para valores faltantes:

IS NULL

Específicamente, no está comparando valores, sino que busca valores perdidos .

Finalmente, en lo que respecta al !=operador, que yo sepa, en realidad no está en ninguno de los estándares, pero es muy compatible. Se agregó para que los programadores de algunos idiomas se sientan más en casa. Francamente, si un programador tiene dificultades para recordar qué idioma está usando, tiene un mal comienzo.

Manngo
fuente
Esta es la misma "lógica" "sin sentido" que @Hove está describiendo en su respuesta. La verdad es que en este contexto no hay necesidad de esa parafernalia extra; se podría suponer fácilmente que cuando estamos comparando algo con a NULLqueremos decir que estamos comparando un valor con 'tener un NULLvalor', no el valor con "el valor indeterminado que NULLestá teniendo la base", pero que no sabemos ", que obviamente no podremos saber nunca. Eso realmente facilitaría las cosas.
Pere
@Pere No diría que es estrictamente "sin sentido", y no estoy seguro de que escribir IS NULLsea ​​mucho más arduo que escribir = NULL. Creo que sería más consistente si WHERE columnA = columnBtuviera la misma interpretación que WHERE columnA = NULL, en lugar de tratar a este último como un caso especial. Recuerda que noNULL es un valor. En los lenguajes de programación donde es legítimo probarlo es porque tiene un significado diferente; no representa algo desconocido, sino un restablecimiento deliberado de un valor. No es así con SQL. variable == nullnull
Manngo
Es por eso que lo puse entre comillas, @Mangoo;) (y también "lógica"). No te enojes conmigo; Estaba hablando del "razonamiento" ANSI, no de su explicación. Estoy de acuerdo en que no hay gastos generales entre IS NULLAND =NULLen su último ejemplo. Pero eche un vistazo al último de Hover. Estoy cansado de experimentarlo una y otra vez, tener que hacer un montón de ¿innecesario? comprobación adicional ...
Pere
1

Me gustaría sugerir este código que hice para encontrar si hay un cambio en un valor, isiendo el nuevo valor y del antiguo (aunque el orden no importa). Para el caso, un cambio de valor a nulo o viceversa es un cambio, pero de nulo a nulo no lo es (por supuesto, de valor a otro valor es un cambio, pero de valor al mismo no lo es).

CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
    @i sql_variant,
    @d sql_variant
)
RETURNS bit
AS
BEGIN
    DECLARE @in bit = 0, @dn bit = 0
    if @i is null set @in = 1
    if @d is null set @dn = 1

    if @in <> @dn
        return 0

    if @in = 1 and @dn = 1
        return 1

    if @in = 0 and @dn = 0 and @i = @d
        return 1

    return 0

END

Para usar esta función, puede

declare @tmp table (a int, b int)
insert into @tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)

---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from @tmp

---- where equal ----
select *,'equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 1

---- where not equal ----
select *,'not equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 0

Los resultados son:

---- in select ----
a   b   =
1   1   1
1   2   0
1   NULL    0
NULL    1   0
NULL    NULL    1

---- where equal ----
1   1   equal
NULL    NULL    equal

---- where not equal ----
1   2   not equal
1   NULL    not equal
NULL    1   not equal

El uso de sql_variant lo hace compatible para una variedad de tipos

Yariv de Botton
fuente