2010-10-14 11 views
9

Así que tiene una simple consulta que devuelve una lista de productosSQL y valores NULL en la cláusula WHERE

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 

Esto devuelve

010-00749-01 00000000-0000-0000-0000-000000000000 
010-00749-01 NULL 

Qué es lo correcto, así que quería sólo los productos cuya CategoryID no es '00000000-0000-0000-0000-000000000000', así que tengo

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 
AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 

Pero esto no devuelve ningún resultado. Así que cambié la consulta a

SELECT  Model, CategoryID 
FROM   Products 
WHERE  (Model = '010-00749-01') 
AND ((CategoryID <> '00000000-0000-0000-0000-000000000000') OR (CategoryID IS NULL)) 

que devuelve resultado previsto a

010-00749-01 NULL 

¿Puede alguien explicar este comportamiento conmigo? MS SQL Server 2008

+3

el artículo de la wiki es bastante bueno para explicar NULL - http://en.wikipedia.org/wiki/Null_%28SQL%29 –

+0

@Russ Cam - deberías haber publicado esto como una respuesta ... – veljkoz

+1

Me sentí fue más una respuesta lmgtfy :) –

Respuesta

9

Consulte la referencia completa en Books Online - de forma predeterminada ANSI_NULLS está activado lo que significa que debe usar el enfoque que ha realizado. De lo contrario, podría desactivar esa configuración al inicio de la consulta para cambiar el comportamiento.

Cuando SET ANSI_NULLS está en ON, una instrucción SELECT que utiliza DONDE Column_name = NULL vuelve cero filas incluso si hay valores nulos en COLUMN_NAME. Una instrucción SELECT que usa WHERE column_name <> NULL devuelve cero filas incluso si hay valores no nulos en column_name.
...
Cuando SET ANSI_NULLS está activado, todas las comparaciones con un valor nulo evalúan a UNKNOWN. Cuando SET ANSI_NULLS está DESACTIVADO, las comparaciones de todos los datos con un valor nulo se evalúan a TRUE si el valor de los datos es NULL.

Aquí está un ejemplo sencillo para demostrar el comportamiento con respecto a las comparaciones contra NULL:

-- This will print TRUE 
SET ANSI_NULLS OFF; 
IF NULL <> 'A' 
    PRINT 'TRUE' 
ELSE 
    PRINT 'FALSE' 

-- This will print FALSE 
SET ANSI_NULLS ON; 
IF NULL <> 'A' 
    PRINT 'TRUE' 
ELSE 
    PRINT 'FALSE' 
+0

Tenga cuidado, establecer ANSI_NULLS en 'off' disminuirá el rendimiento y aumentará las lecturas lógicas. Activarlo afecta el plan de consulta. – vol7ron

+0

@ Vol7ron Realmente mereció un voto a favor ?! Eso es duro para lo que es una respuesta correcta. Si honestamente siente que merece un voto a la baja, es justo, pero el mensaje parece extraño y no un voto honesto – AdaTheDev

+0

¿Qué merecía un voto a favor? No creo que merezca una o más. Es una respuesta. No iría tan lejos para decir que es "correcto" tampoco. La implementación de esto tendrá un impacto en el rendimiento, pero lo más importante es que técnicamente no es estándar SQL, en el momento en que lo implemente, se está desviando de ISO. Una de las mejores cosas de SQL es la capacidad de ir de una plataforma a otra, lo estás abandonando aquí. 'Coalesce' es una mejor solución. Como dije, si le preocupa el impacto en el rendimiento, entonces indexe ese campo con la función, de lo contrario, limpie los datos subyacentes. – vol7ron

1

vistazo a esto:

1=1  --true 
1=0  --false 
null=null --false 
null=1  --false 

1<>1  --false 
1<>0  --true 
null<>null --false 
null<>1 --false <<<--why you don't get the row with: AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 
+3

Técnicamente, SQL utiliza un sistema de lógica de tres valores, por lo que todas sus comparaciones con NULL producen DESCONOCIDO en lugar de FALSO. Ver: [SQL y la trampa de la lógica de tres valores] (http://www.simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of-three-valued-logic/) –

+0

lo llaman 'falso' o' desconocido', en realidad no importa, porque la fila no está incluida en el conjunto de resultados, de lo que se trata la pregunta. –

1

Básicamente, un NULL es el ausencia de cualquier valor. Por lo tanto, intentar comparar NULL en CategoryId con un valor varchar en la consulta siempre dará como resultado una evaluación falsa.

Es posible que desee probar el uso de la función COALESCE, algo así como:

SELECT  ModelId, CategoryID 
FROM  Products 
WHERE  (ModelId = '010-00749-01') 
AND  (COALESCE(CategoryID, '') <> '00000000-0000-0000-0000-000000000000') 

EDITAR

Como señaló AdaTheDev la función COALESCE negará cualquier índice que puedan existir en la columna CategoryID, que puede afectar el plan de consulta y el rendimiento.

+1

Tenga cuidado con este enfoque, ya que el COALESCE podría resultar en un plan de ejecución menos óptimo al evitar una búsqueda de índice en esa columna – AdaTheDev

+0

Ada es correcta, el COALESCE tiene un efecto en el plan de ejecución. Editaré mi respuesta para incluir. –

0

Usted puede tratar de usar la función Coalesce para establecer un valor por defecto para los campos que tienen null:

SELECT Model , CategoryID 
    FROM  Products 
    WHERE  Model = '010-00749-01' 
    AND  Coalesce(CategoryID,'') <> '00000000-0000-0000-0000-000000000000' 

Creo que el problema radica en la comprensión de NULL que básicamente significa "nada". No se puede comparar nada con nada, al igual que no se puede dividir un número entre 0. Solo se trata de reglas de matemática/ciencia.

Editar: Como Ada ha señalado, esto podría hacer que un campo indexado ya no use un índice.

Solución:

  • Puede crear un índice mediante la función se unen: por ejemplo create index ... coalesce(field)
  • Usted puede agregar una restricción not null para evitar valores nulos vez que aparecen
  • Un estándar de facto de la mía es de siempre asigne valores predeterminados y nunca permita nulos
+2

Tenga cuidado con este enfoque, ya que COALESCE podría resultar en un plan de ejecución menos óptimo al evitar una búsqueda de índice en esa columna – AdaTheDev

+0

Esto podría ser cierto, sin embargo, puede crear un índice como 'coalesce (field)', o agregar un no es una restricción nula para evitar que aparezcan NULL.Un estándar de facto mío es asignar siempre valores por defecto y nunca permitir nulos. – vol7ron

2

En general, debe recordar que NULL generalmente significa DESCONOCIDO. Eso significa que si dices CategoryID <> '00000000-0000-0000-0000-000000000000', debes asumir que la consulta solo arrojará valores que SABE que cumplirán tus criterios. Dado que hay un resultado NULO (DESCONOCIDO), en realidad no se sabe si ese registro cumple con sus criterios y, por lo tanto, no se devolverá en el conjunto de datos.

+0

Mientras que las otras respuestas contienen más detalles, me gusta esta por la simplicidad. Es comprensible incluso para un desarrollador no técnico, y por lo tanto valioso para los desarrolladores más nuevos. +1. – David

Cuestiones relacionadas