2009-03-25 7 views
5

W mojej tabeli mam kolumnę z zerową liczbą bitów (starszy system ...), a inny programista dokonał ostatnio zmiany w procedurze przechowywanej, aby pokazać tylko wartości, w których kolumna bitowa nie była prawdą (1). Ponieważ jest to kolumna zerowa, zauważyliśmy, że jeśli kolumna ma wartość NULL, rekord nie był odbierany. Dlaczego to?SQL: Dlaczego wartości NULL są odfiltrowane w ramach tej klauzuli where?

Zarówno inny programista, jak i ja zgadzamy się, że NULL <> 1 ... Czy jest to błąd w SQL lub został zaprojektowany w ten sposób? Wygląda jak wada projektowa.

Aktualny Kod:

(VoidedIndicator <> 1) 

Proponowane Fix:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL) 

Wyjaśnienie (Jon Erickson)

VoidedIndicator jest polem nieco pustych więc może mieć następujące wartości: NULL, 0, o R1

Gdy instrukcja SQL jest tworzony z WHERE takich jak (VoidedIndicator <> 1) dostajemy tylko rekordy zwrócone które mają VoidedIndicator == 0, ale spodziewaliśmy się zarówno VoidedIndicator == 0 i VoidedIndicator IS NULL. Dlaczego to?

Odpowiedz

11

Z Wikipedia entry on NULL:

Na przykład WHERE lub warunkowe oświadczenie może porównać wartości danej kolumny ze stałą. Jest to często błędnie zakładane, że brakująca wartość będzie "mniejsza niż" lub "nie równa się" stałej, jeśli to pole zawiera wartość Null, ale w rzeczywistości takie wyrażenia zwracają nieznane. przykładem jest poniżej:

-- Rows where num is NULL will not be returned, 
-- contrary to many users' expectations. 
SELECT * FROM sometable WHERE num <> 1; 

Zasadniczo jakiekolwiek porównanie między NULL i coś innego, czy to z = lub <> nie będzie prawdą.

Jako inny odsyłającym MSDN T-SQL page on <> stany:

Porównuje dwa wyrażenia (a operator porównania ). Gdy porównasz wyrażenia inne niż , wynik jest PRAWDZIWY, jeśli lewy operand nie jest równy prawemu operandowi ; w przeciwnym razie wynikiem jest FAŁSZ.Jeśli jeden lub oba operandy są NULL, zobacz SET ANSI_NULLS (Transact-SQL).

Strona SET ANSI_NULLS następnie stwierdza:

Gdy zestaw ANSI_NULLS jest ON, SELECT stwierdzenie, że używa WHERE column_name = NULL zwraca zero wierszy, nawet jeśli istnieją wartości null w column_name. Instrukcja SELECT, która używa WHERE nazwa_kolumny <> NULL zwraca zero wierszy , nawet jeśli istnieją niepuste wartości w nazwa_kolumny.

...

Gdy zestaw ANSI_NULLS jest włączona, wszystkie porównania przeciwko wartość null ocenia się nieznany. Gdy SET ANSI_NULLS jest WYŁĄCZONA, porównanie wszystkich danych z wartością zerową jest oceniane na TRUE, jeśli wartość danych wynosi NULL.

3

To nie jest błąd.

NULL nie jest równy cokolwiek, nawet NULL (NULL = NULL zwraca FALSE).

Zazwyczaj wartości NULL również nie są indeksowane. Generalnie złym pomysłem jest poleganie na określonej wartości lub NULL. Zależnie od tego, co przechowujesz w kolumnie, możesz lepiej użyć wartości atrapa lub wartownika zamiast używać NULL, aby wskazać jakieś znaczenie.

+0

Więc jeśli NULL nie jest równy cokolwiek, co mówisz, to w jaki sposób NULL nie zostanie w to uwzględnione? Kolumna <> 1 ... NULL nie równa się 1? Poprawny? – RSolberg

+0

Każde porównanie z wartością NULL zwraca wartość false, tak więc NULL <> 1 ma wartość false. Do tego służy IS NULL lub IS NOT NULL. – cletus

+0

Najlepszym sposobem myślenia o wartościach zerowych w terminologii bazy danych, słusznie lub niesłusznie, jest to, że wartość pusta jest "nieznana", dlatego nie może być porównywana z inną wartością zerową ani porównywana z konkretną wartością –

0

Można także: IsNull (VoidedIndicator, 1) <> 1

+0

Zły pomysł na wydajność, chyba że masz funkcjonalny indeks dla tego typu rzeczy. – cletus

+0

Miałem zamiar powiedzieć, że myślałem, że IsNull() miał problemy z wydajnością ... – RSolberg

+0

@letus, który rozważa, że ​​ma scenariusz, który faktycznie potrzebuje tej optymalizacji. Zgadzam się jednak na stosowanie wartości domyślnej tam, gdzie to możliwe/odpowiednie. – eglasius

0

Ponieważ WHERE wybiera tylko wiersze, gdy warunek jest prawdziwy.

Gdy jeden z operandów ma wartość NULL, warunek zwykle jest oceniany jako NIEZNANY (w przybliżeniu równoważny wartości NULL), a zatem nie jest prawdziwy. Obowiązuje zarówno dla "column = 1" i "column <> 1"; jeśli kolumna ma wartość NULL, warunek wyszukiwania kończy się niepowodzeniem.

Dlatego zaleca się unikać kolumn NULL, gdy tylko jest to możliwe.

+0

Czy unikasz również wartości całkowitej zero, ponieważ dzielenie przez zero powoduje błąd? –

+0

Może to zależeć od serwera, ale są przyzwoite, że jeśli napiszesz "column/0", a kolumna będzie pusta, kod podziału sprawdzi, czy którykolwiek argument jest zerowy i zwraca wartość null przed wygenerowaniem "dzielenia przez zero" błąd. Jeśli jednak wiesz, że "kolumna" ma wartość null, dlaczego ją dzielisz? –

+0

I dlaczego w ogóle dzielicie się przez zero? Myślę, że nierozsądnie byłoby polegać na wartościach zerowych, które zapobiegają błędom dzielenia przez zero, ale jeśli podzielisz zero na "przypadkowo", prawdopodobnie nie otrzymasz błędu. –

1

Inni ludzie mają rację, że NULL <> 1 nie jest prawdziwy, dlatego nie spełnia warunku WHERE.

Proponowana poprawka opisać to najlepszy sposób obsługiwać go:

(VoidedIndicator <> 1 OR VoidedIndicator IS NULL) 

SQL-99 ma orzeczenie, które pomagają w tym przypadku nazywa IS DISTINCT FROM:

(VoidedIndicator IS DISTINCT FROM 1) 

to orzeczenie będzie zachowują się dokładnie tak samo, jak proponowana poprawka. Niestety, Microsoft SQL Server nie obsługuje jeszcze wersji IS DISTINCT FROM.

+0

Dzięki za wgląd, nie natknąłem się na ODNOWIONE OD wcześniej. Czy to jeszcze nie zostało zaimplementowane w SQL Server 2008? –

+0

Dobrze. Nie mogę znaleźć IS DISTINCT FROM w dokumentacji online MS SQL Server 2008, natomiast znajduję predykat IS NULL i funkcję ISNULL(). –

+0

Obsługa PostgreSQL, IBM DB2 i Firebird IS DISTINCT FROM. Oracle i Microsoft nie. MySQL obsługuje operatora "<=>". –

0

NULL <> 1 ocenia (teoretycznie) "może", co oznacza, że ​​rekord nie zostanie zwrócony.

12

Wiele dobrych odpowiedzi, ale pozwól mi podać naprawdę zwięzłą wersję.

do SQL, Null wcale nie oznacza „Brak wartości”, to znaczy „Nieznana wartość”

Mając to na uwadze, należy rozważyć odpowiedź na pytanie prosicie SQL w prostym języku angielskim.

Q: Is this unknown value not equal to 1? 
A: I don't know, there is no way to tell without knowing the value. 

Hence Null<>1 = Null