2010-10-14 12 views
9

Così ho una semplice query che restituisce un elenco di prodottiSQL e Null I valori in cui la clausola

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

Ciò restituisce

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

che è corretto, così ho voluto solo i prodotti la cui IDCategoria non è '00000000-0000-0000-0000-000000000000' quindi ho

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

Ma questo non restituisce alcun risultato. Così ho cambiato la query per

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

che restituisce risultato atteso

010-00749-01 NULL 

Qualcuno può spiegare questo comportamento a me? MS SQL Server 2008

+3

l'articolo wiki è abbastanza bravo a spiegare NULL - http://en.wikipedia.org/wiki/Null_%28SQL%29 –

+0

@Russ Cam - avresti dovuto postare questo come risposta ... – veljkoz

+1

Mi sono sentito era più di una risposta lmgtfy :) –

risposta

9

Controlla il riferimento completo su Books Online - per impostazione predefinita ANSI_NULLS sta per significare che avresti bisogno di utilizzare l'approccio che hai fatto. Altrimenti, è possibile disattivare tale impostazione all'inizio della query per cambiare il comportamento.

Quando SET ANSI_NULLS è ON, un SELECT dichiarazione che utilizza WHERE nome_colonna = restituisce NULL zero righe, anche se non ci sono valori nulli in column_name. A SELECT statement che utilizza WHERE column_name <> NULL restituisce zero righe anche se non ci sono valori non nulli in column_name.
...
Se SET ANSI_NULLS è ON, tutti i confronti con un valore nullo vengono valutati su UNKNOWN. Quando SET ANSI_NULLS è disattivato, i confronti di tutti i dati rispetto a un valore nullo rappresentano TRUE se il valore dei dati è NULL.

Ecco un semplice esempio per illustrare il comportamento per quanto riguarda i confronti contro 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

Fai attenzione, impostando ANSI_NULLS su "off" ridurrà le prestazioni e aumenterà le letture logiche. L'attivazione ha effetto sul piano di query. – vol7ron

+0

@ Vol7ron Davvero meritato un downvote ?! Ciò v duro per ciò che è una risposta corretta. Se lo ritieni onestamente giustificabile, è abbastanza giusto ma sembra strano e non è un voto onesto – AdaTheDev

+0

Che cosa merita un downvote? Non penso che meriti un down o un up. È una risposta Non andrei così lontano da dire che è "corretto" sia. L'implementazione di questo richiederà un successo in termini di prestazioni, ma ancora più importante tecnicamente non è lo standard SQL, nel momento in cui lo implementate, vi allontanate dall'ISO. Una delle cose migliori di SQL è la possibilità di passare da una piattaforma all'altra, lo stai dando qui. 'Coalesce' è una soluzione migliore. Come ho affermato, se sei preoccupato dell'impatto sulle prestazioni, indicizza quel campo con la funzione, altrimenti ripulisci i dati sottostanti. – vol7ron

1

un'occhiata a questo:

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

Tecnicamente SQL utilizza un sistema logico a tre valori, quindi tutti i tuoi confronti con NULL danno SCONOSCIUTO piuttosto che FALSO. Vedi: [SQL e il rullante della logica a tre valori] (http://www.simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of-three-valued-logic/). –

+0

chiamalo 'false' o' unknown', non ha molta importanza, perché la riga non è inclusa nel set di risultati, che è l'oggetto della domanda. –

1

In sostanza, un NULL è il assenza di qualsiasi valore. Quindi provare a confrontare il NULL in CategoryId con un valore varchar nella query genererà sempre una valutazione errata.

Si potrebbe provare a utilizzare la funzione COALESCE, qualcosa di simile:

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

EDIT

Come notato da AdaTheDev la funzione COALESCE negare eventuali indici che possono esistere sulla colonna IDCategoria, che può influenzare il piano di query e le prestazioni.

+1

Prestare attenzione a questo approccio, poiché COALESCE potrebbe comportare un piano di esecuzione meno ottimale impedendo la ricerca di un indice su tale colonna – AdaTheDev

+0

Ada è corretta, il COALESCE ha un effetto sul piano di esecuzione. Modificherà la mia risposta per includere. –

0

Si può provare a utilizzare la funzione Coalesce per impostare un valore predefinito per i campi che hanno null:

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

Credo che il problema sta nella vostra comprensione di NULL che in pratica significa "niente". Non puoi confrontare nulla con niente, molto come non puoi dividere un numero di 0. Sono solo regole di matematica/scienze.

Modifica: Come indicato da Ada, ciò potrebbe causare un campo indicizzato per non utilizzare più un indice.

Soluzione:

  • È possibile creare un indice utilizzando la funzione di COALESCE: ad esempio create index ... coalesce(field)
  • È possibile aggiungere un vincolo not null per evitare che i NULL da mai apparire
  • uno standard de facto di mia è a assegna sempre valori predefiniti e non consentire mai valori nulli
+2

Fai attenzione a questo approccio, poiché COALESCE potrebbe portare a un piano di esecuzione meno ottimale impedendo la ricerca di un indice su quella colonna – AdaTheDev

+0

Ciò potrebbe essere vero, tuttavia, puoi creare un indice come 'coalizione (campo)', o aggiungere un vincolo non nullo per impedire la visualizzazione di NULL.Uno standard di fatto mio è sempre assegnare valori predefiniti e mai consentire null. – vol7ron

2

In generale, è necessario ricordare che NULL generalmente significa SCONOSCIUTO. Ciò significa che, se si dice CategoryID <> '00000000-0000-0000-0000-000000000000', si deve presupporre che la query restituirà solo i valori che SAI soddisferanno i criteri. Poiché esiste un risultato NULL (UNKNOWN), in realtà non sa se quel record soddisfa i tuoi criteri e pertanto non verrà restituito nel set di dati.

+0

Mentre le altre risposte contengono più dettagli, mi piace questo per via della semplicità. È comprensibile anche per un non-techie, e quindi prezioso per i nuovi sviluppatori. +1. – David

Problemi correlati