Na serwerze SQL, jeśli masz nullParam=NULL
klauzulę WHERE, zawsze przyjmuje ona wartość false. Jest to sprzeczne z intuicją i spowodowało wiele błędów. Rozumiem, że słowa kluczowe IS NULL
i IS NOT NULL
słowa kluczowe to właściwy sposób. Ale dlaczego serwer SQL zachowuje się w ten sposób?
sql
sql-server
null
Byron Whitlock
źródło
źródło
Odpowiedzi:
Pomyśl o wartości zerowej jako „nieznanej” w tym przypadku (lub „nie istnieje”). W żadnym z tych przypadków nie możesz powiedzieć, że są równe, ponieważ nie znasz wartości żadnego z nich. Tak więc null = null przyjmuje wartość nieprawdziwą (fałszywą lub zerową, w zależności od systemu), ponieważ nie znasz wartości, które mówią, że są równe. To zachowanie jest zdefiniowane w standardzie ANSI SQL-92.
EDYCJA: To zależy od ustawień ansi_nulls . jeśli masz wyłączone ANSI_NULLS, to zostanie ocenione jako prawda. Uruchom następujący kod na przykład ...
źródło
(NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...
- ponieważ cóż, jeśli nie jest to liczba, po prostu nie możesz wiele o tym powiedzieć; to jest coś nieznanego. Koncepcja jest rozsądna, nawet jeśli jest nieintuicyjna dla ludzi, którzy nigdy wcześniej jej nie widzieli.NULL
wyrażenie SQL może być traktowane jako odrębna zmienna matematyczna. Zatem wyrażenieNULL = NULL
powinno być traktowane jako zmiennex = y
, gdziex
iy
są niezwiązane. Jeśli ktoś cię zapyta, jaka jest wartośćx = y
? Jedyną rozsądną odpowiedzią jest „trochęz
”. Więc mamy(x = y) = z
- lub zapisywania go z powrotem do SQL(NULL = NULL) = NULL
.Ile lat ma Frank? Nie wiem (null).
Ile lat ma Shirley? Nie wiem (null).
Czy Frank i Shirley są w tym samym wieku?
Prawidłowa odpowiedź powinna brzmieć „nie wiem” (zero), a nie „nie”, ponieważ Frank i Shirley mogą być w tym samym wieku, po prostu nie wiemy.
źródło
null = null
plonyFALSE
nieNULL
.Mam nadzieję, że tutaj wyjaśnię swoje stanowisko.
Ta
NULL = NULL
ocenaFALSE
jest błędna. Hacker i Mister odpowiedzieli poprawnieNULL
. Oto dlaczego. Dewayne Christensen napisał do mnie w komentarzu do Scotta Iveya :Mogą być różne lub równe, nie wiadomo, dopóki jeden nie otworzy obu prezentów. Kto wie? Zaprosiłeś dwie osoby, które się nie znają i obie zrobiły Ci ten sam prezent - rzadki, ale nie niemożliwy § .
A więc pytanie: czy te dwa NIEZNANE przedstawiają się tak samo (równe, =)? Prawidłowa odpowiedź to: NIEZNANA (tj
NULL
.).Ten przykład miał na celu zademonstrowanie, że „.. (
false
lubnull
, w zależności od systemu) ..” jest poprawną odpowiedzią - nie jest, tylkoNULL
jest poprawna w 3VL (czy możesz zaakceptować system, który daje błędne odpowiedzi? )Prawidłowa odpowiedź na to pytanie musi podkreślać te dwie kwestie:
Powtarzam więc: SQL nie jest dobrym sposobem na zmuszanie do interpretacji zwrotnej właściwości równości, która stwierdza, że:
.. w 3VL (
TRUE
,FALSE
,NULL
). Oczekiwanie ludzi byłoby zgodne z 2VL (TRUE
,FALSE
co nawet w SQL jest poprawne dla wszystkich innych wartości), tj.x = x
Zawsze obliczane doTRUE
, dla dowolnej możliwej wartości x - bez wyjątków.Zauważ również, że wartości NULL są poprawnymi „ nie-wartościami ” (jak udają ich apologeci), które można przypisać jako wartości atrybutów (??) jako część zmiennych relacji. Są to więc dopuszczalne wartości każdego typu (domeny), a nie tylko typu wyrażeń logicznych.
I o to mi chodziło :
NULL
jako wartość jest „dziwną bestią”. Bez eufemizmu wolę powiedzieć: nonsens .Myślę, że to sformułowanie jest dużo jaśniejsze i mniej dyskusyjne - przepraszam za moją słabą znajomość angielskiego.
To tylko jeden z problemów NULLów. Lepiej ich całkowicie unikać, jeśli to możliwe.
§ martwimy się tutaj o wartości , a więc fakt, że te dwa prezenty są zawsze dwoma różnymi przedmiotami fizycznymi, nie jest uzasadnionym zarzutem; jeśli nie jesteś przekonany, przepraszam, to nie jest miejsce na wyjaśnienie różnicy między semantyką wartości i "obiektu" (algebra relacyjna ma semantykę wartości od samego początku - patrz zasada informacyjna Codda; Myślę, że niektórzy implementatorzy SQL DBMS nie obchodzi mnie nawet wspólna semantyka).
§§ o ile wiem, jest to aksjomat akceptowany (w takiej czy innej formie, ale zawsze interpretowany w 2VL) od starożytności i to właśnie dlatego , że jest tak intuicyjny. 3VLs (w rzeczywistości jest rodziną logiki) to znacznie nowszy rozwój (ale nie jestem pewien, kiedy został opracowany po raz pierwszy).
Uwaga boczna: jeśli ktoś wprowadzi typy Bottom , Unit i Option jako próby uzasadnienia SQL NULL, przekona mnie dopiero po dość szczegółowym badaniu, które pokaże, jak implementacje SQL z NULLami mają system typów dźwięku i wyjaśnię, na koniec, czym naprawdę są wartości NULL (te „wartości-nie-wartości”).
W dalszej części zacytuję niektórych autorów. Jakikolwiek błąd lub przeoczenie jest prawdopodobnie mój, a nie oryginalnych autorów.
Joe Celko o wartościach NULL SQL
Widzę, że Joe Celko jest często cytowany na tym forum. Najwyraźniej jest tu bardzo szanowanym autorem. Więc powiedziałem sobie: „co on napisał o NULLach SQL? Jak wyjaśnia liczne problemy NULL-ów?”. Jeden z moich znajomych ma ebookową wersję SQL Joe Celko for smarties: zaawansowane programowanie SQL, 3. wydanie . Zobaczmy.
Najpierw spis treści. Najbardziej uderza mnie to, ile razy pojawia się NULL i w najróżniejszych kontekstach:
i tak dalej. Dla mnie to brzmi „paskudny przypadek specjalny”.
Omówię niektóre z tych przypadków z fragmentami tej książki, próbując ograniczyć się do najważniejszych z powodów związanych z prawem autorskim. Myślę, że te cytaty mieszczą się w doktrynie „dozwolonego użytku” i mogą nawet zachęcać do zakupu książki - więc mam nadzieję, że nikt nie będzie narzekał (w przeciwnym razie będę musiał usunąć większość, jeśli nie wszystkie). Ponadto z tego samego powodu powstrzymam się od zgłaszania fragmentów kodu. Przepraszam za to. Kup książkę, aby przeczytać o uzasadnieniu opartym na danych.
Numery stron w nawiasach w dalszej części.
Znowu ten nonsens „wartość, ale niezupełnie wartość”. Reszta wydaje mi się całkiem rozsądna.
A propos SQL, NULL i Infinite:
Implementacje SQL nie zdecydowały, co tak naprawdę oznacza NULL w określonych kontekstach:
Joe Celko cytujący Davida McGoverana i CJ Date:
NULL jako narkomania :
Moim jedynym zastrzeżeniem jest „właściwe ich używanie”, co źle współgra z określonymi zachowaniami implementacyjnymi.
(separator)
Ale NIEZNANY sam w sobie jest źródłem problemów, dlatego CJ Date w cytowanej poniżej książce zaleca w rozdziale 4.5. Unikanie wartości null w SQL :
Przeczytaj „ASIDE” w UNKNOWN, do której link znajduje się poniżej.
(separator)
Zarzut: wartości NULL dezorientują nawet osoby dobrze znające SQL, patrz poniżej.
(separator)
(separator)
(separator)
(separator)
(separator)
(separator)
Omówienie GROUP BY:
Oznacza to, że klauzula GROUP BY NULL = NULL nie daje wartości NULL, jak w 3VL, ale przyjmuje wartość TRUE.
Standard SQL jest mylący:
I tak dalej. Myślę, że Celko wystarczy.
Data CJ w SQL NULL
CJ Date jest bardziej radykalnym podejściem do wartości NULL: unikaj wartości NULL w SQL, kropka. W rzeczywistości rozdział 4 jego teorii SQL i teorii relacyjnej: Jak pisać dokładny kod SQL jest zatytułowany „BEZ DUPLIKATÓW, BEZ ZERÓW NULL ”, z podrozdziałami „4.4 Co jest nie tak z wartościami zerowymi?” oraz „4.5 Unikanie Null w SQL” (kliknij link: dzięki Google Books możesz czytać niektóre strony on-line).
Fabian Pascal na SQL NULL
Z jego praktycznych zagadnień w zarządzaniu bazami danych - odniesienie dla praktyka myślącego (brak fragmentów on-line, przepraszam):
źródło
NULL
nie jest wartością.(NULL = NULL) -> FALSE
. Cytując dokumentację dlaANSI_NULLS
: „Gdy określono ON, wszystkie porównania z wartością zerową są obliczane na UNKNOWN . Gdy określono OFF, porównania wartości innych niż UNICODE z wartością null dają PRAWDA, jeśli obie wartości są równe NULL.”Może to zależy, ale pomyślałem, że
NULL=NULL
wartości sąNULL
podobne do większości operacji z NULL jako operandem.źródło
To, że nie wiesz, czym są dwie rzeczy, nie oznacza, że są równe. Jeśli
NULL
myślisz o „NULL” (ciąg znaków), prawdopodobnie potrzebujesz innego testu równości, takiego jakIS DISTINCT FROM
ORAZ PostgresqlaIS NOT DISTINCT FROM
Z dokumentacji PostgreSQL na temat „Funkcje porównawcze i operatory”
źródło
Pojęcie NULL jest co najmniej wątpliwe. Codd przedstawił model relacyjny i koncepcję NULL w kontekście (i zaproponował więcej niż jeden rodzaj NULL!) Jednak teoria relacyjna ewoluowała od czasu oryginalnych prac Codda: niektóre z jego propozycji zostały od tego czasu odrzucone (np. Klucz podstawowy) i inni nigdy się nie przyjęli (np. operatorzy theta). We współczesnej teorii relacyjnej (powinienem podkreślić, prawdziwie relacyjnej teorii) NULL po prostu nie istnieje. Zobacz trzeci manifest.http://www.thethirdmanifesto.com/
Język SQL boryka się z problemem kompatybilności wstecznej. NULL trafił do SQL i utknęliśmy z tym. Prawdopodobnie implementacja
NULL
w SQL jest błędna (implementacja SQL Servera komplikuje sprawę jeszcze bardziej ze względu na swojąANSI_NULLS
opcję).Zalecam unikanie używania kolumn o wartości NULL w tabelach podstawowych.
Chociaż może nie powinienem się kusić, po prostu chciałem wprowadzić własne poprawki dotyczące tego, jak
NULL
działa w SQL:NULL
=NULL
szacuje się doUNKNOWN
.UNKNOWN
jest wartością logiczną.NULL
to wartość danych.Łatwo to udowodnić np
SELECT NULL = NULL
poprawnie generuje błąd w SQL Server. Gdyby wynik był wartością danych, spodziewalibyśmy się zobaczyć
NULL
, jak sugerują niektóre odpowiedzi tutaj (błędnie).Wartość logiczna
UNKNOWN
jest traktowana inaczej odpowiednio w SQL DML i SQL DDL.W SQL DML
UNKNOWN
powoduje usuwanie wierszy z zestawu wyników.Na przykład:
INSERT
Uda do tego wiersza, choćCHECK
stan postanawiaNULL = NULL
. Jest to określone w standardzie SQL-92 („ANSI”):Przeczytaj to uważnie, postępując zgodnie z logiką.
Mówiąc prostym językiem, nasz nowy wiersz powyżej przedstawia „korzyść z wątpliwości” co do bycia
UNKNOWN
i pozwolenia na przejście.W SQL DML reguła
WHERE
klauzuli jest znacznie łatwiejsza do przestrzegania:W zwykłym języku angielskim wiersze, których wynikiem jest wartość,
UNKNOWN
są usuwane z zestawu wyników.źródło
Na technecie jest dobre wyjaśnienie, jak działają wartości zerowe.
Brak oznacza nieznane.
Dlatego wyrażenie boolowskie
wartość = null
nie daje wartości false, zwraca wartość null, ale jeśli jest to końcowy wynik klauzuli where, to nic nie jest zwracane. Jest to praktyczny sposób, aby to zrobić, ponieważ zwrócenie wartości zerowej byłoby trudne do wyobrażenia.
Interesujące i bardzo ważne jest zrozumienie następujących kwestii:
Jeśli w zapytaniu mamy
i
następnie
„value = @ param” zwraca wartość null
„@param is null”
zwraca wartość true „id = @ anotherParam” przyjmuje wartość true
Zatem wyrażenie, które ma zostać ocenione, staje się
(null Lub true) I prawda
Moglibyśmy ulec pokusie, aby pomyśleć, że tutaj „null Or true” zostanie oszacowane na null, a zatem całe wyrażenie stanie się puste, a wiersz nie zostanie zwrócony.
Tak nie jest. Czemu?
Ponieważ „null Or true” oblicza wartość true, co jest bardzo logiczne, ponieważ jeśli jeden operand jest prawdziwy z operatorem Or, to niezależnie od wartości drugiego operandu, operacja zwróci wartość true. Dlatego nie ma znaczenia, że drugi operand jest nieznany (zerowy).
Więc w końcu mamy true = true i tym samym wiersz zostanie zwrócony.
Uwaga: z tą samą krystalicznie czystą logiką, która „null Or true” przyjmuje wartość true, „null And true” przyjmuje wartość null.
Aktualizacja:
Ok, żeby wszystko było kompletne, chcę tutaj dodać resztę, co okazuje się całkiem zabawne w stosunku do powyższego.
„null Or false” daje wartość null, „null And false” przyjmuje wartość „false”. :)
Logika jest oczywiście tak samo oczywista jak wcześniej.
źródło
Ponieważ
NULL
oznacza „nieznaną wartość” i dwie nieznane wartości nie mogą być równe.Jeśli więc zgodnie z naszą logiką
NULL
nr 1 równa sięNULL
nr 2, to musimy jakoś to powiedzieć:gdzie znana wartość
-1
nr 1 jest równa-1
nr 2źródło
nullParam1 = -1
anullParam2 =NULL
i katastrofaISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
Wszystkie odpowiedzi wydają się pochodzić z perspektywy CS, więc chcę dodać jedną z perspektywy programisty.
Dla programisty NULL jest bardzo przydatne. Odpowiedzi tutaj mówią, że NULL oznacza nieznane, a może w teorii CS to prawda, nie pamiętaj, minęło trochę czasu. Jednak w rzeczywistym rozwoju, przynajmniej z mojego doświadczenia, zdarza się to około 1% czasu. Pozostałe 99% jest używane w przypadkach, gdy wartość nie jest NIEZNANA, ale WIADOMO, ŻE JEST NIEOBECNA.
Na przykład:
Client.LastPurchase
, dla nowego klienta. Nie wiadomo, wiadomo, że jeszcze nie dokonał zakupu.Podczas korzystania z ORM z mapowaniem Table per Class Hierarchy , niektóre wartości po prostu nie są mapowane dla niektórych klas.
Podczas odwzorowywania struktury drzewa zwykle będzie miał korzeń
Parent = NULL
I wiele więcej...
Jestem pewien, że większość programistów w pewnym momencie napisała
WHERE value = NULL
, nie otrzymała żadnych wyników i tak właśnie nauczyła sięIS NULL
składni. Spójrz tylko, ile głosów ma to pytanie i powiązane.Bazy danych SQL to narzędzie, które należy projektować w sposób najłatwiejszy do zrozumienia dla użytkowników.
źródło
NULL nie jest niczym, nawet sobie. Moim osobistym sposobem zrozumienia zachowania NULL jest unikanie używania go w jak największym stopniu :).
źródło
Pytanie:
czy jedna niewiadoma równa się drugiej niewiadomej?
(NULL = NULL) Na
to pytanie nikt nie może odpowiedzieć, więc domyślnie przyjmuje wartość true lub false w zależności od ustawienia ansi_nulls.
Jednak pytanie:
czy ta nieznana zmienna jest nieznana?
To pytanie jest zupełnie inne i można na nie odpowiedzieć prawdziwie.
nullVariable = null porównuje wartości
nullVariable is null porównuje stan zmiennej
źródło
Zamieszanie wynika z poziomu pośrednictwa (abstrakcji), który wynika z użycia NULL .
Wracając do analogii „co jest pod choinką”, „Nieznane” opisuje stan wiedzy o tym, co znajduje się w ramce A.
Jeśli więc nie wiesz, co znajduje się w polu A, mówisz, że jest to „Nieznane”, ale to nie znaczy, że „Nieznane” znajduje się w polu . W pudełku jest coś innego niż nieznane, być może jakiś przedmiot lub być może nic nie jest w pudełku.
Podobnie, jeśli nie wiesz, co znajduje się w polu B, możesz oznaczyć swój stan wiedzy o zawartości jako „Nieznany”.
Tak jest też haczyk: Twój stan wiedzy na temat Box A jest równa swojego stanu wiedzy na temat Box B . (Twój stan wiedzy w obu przypadkach to „Nieznany” lub „Nie wiem, co jest w pudełku”). Ale zawartość pudełek może być równa lub nie.
Wracając do SQL, najlepiej byłoby, gdybyś mógł porównywać wartości tylko wtedy, gdy wiesz, jakie one są. Niestety etykieta opisująca brak wiedzy jest przechowywana w samej komórce , więc kusi nas, aby użyć jej jako wartości. Nie powinniśmy jednak używać tego jako wartości, ponieważ prowadziłoby to do tego, że „zawartość pola A jest równa zawartości pola B, gdy nie wiemy, co jest w polu A i / lub nie wiemy, co jest w polu B. (Logicznie rzecz biorąc, implikacja „jeśli nie wiem, co jest w polu A i jeśli nie wiem, co jest w polu B, to co jest w polu A = co jest w polu B” jest fałszywa).
Yay, Dead Horse.
źródło
MSDN ma ładny opis artykuł na temat wartości zerowych i logiki trzech stanów, które generują.
Krótko mówiąc, specyfikacja SQL92 definiuje NULL jako nieznaną, a NULL użyte w następujących operatorach powoduje nieoczekiwane wyniki dla niewtajemniczonych:
źródło
wartość null jest nieznana w sql, więc nie możemy oczekiwać, że dwie niewiadome będą takie same.
Możesz jednak uzyskać to zachowanie ustawiając ANSI_NULLS na Off (domyślnie włączone) Będziesz mógł użyć operatora = dla wartości null
źródło
null
, naucz się go rozumieć lub po prostu zmodyfikuj tabelę, aby zawierała typy int i zaktualizuj kolumny.Pracujesz dla rządu, rejestrując informacje o obywatelach. Obejmuje to dowód osobisty każdej osoby w kraju. Dziecko zostało pozostawione pod drzwiami kościoła jakieś 40 lat temu, nikt nie wie, kim są jego rodzice. Identyfikator ojca tej osoby to
NULL
. Istnieją dwie takie osoby. Policz osoby, które mają ten sam identyfikator ojca z co najmniej jedną inną osobą (osobami będącymi rodzeństwem). Czy ty też liczysz te dwa?Odpowiedź brzmi: nie, nie, bo nie wiemy, czy to rodzeństwo, czy nie.
Załóżmy, że nie masz
NULL
opcji i zamiast tego użyj pewnej z góry określonej wartości do reprezentowania „nieznanego”, być może pustego ciągu znaków lub cyfry 0 lub znaku * itd. Wtedy w zapytaniach pojawi się * = * , 0 = 0, i „” = „”, itd. To nie jest to, czego chcesz (jak na powyższym przykładzie), i jak często możesz zapomnieć o tych przypadkach (powyższy przykład jest wyraźnym przypadkiem marginalnym poza zwykłym codziennym myśleniem ), wtedy potrzebujesz języka do zapamiętania, żeNULL = NULL
nie jest prawdą.Potrzeba jest matka wynalazku.
źródło
To tylko dodatek do innych wspaniałych odpowiedzi:
źródło
Jeśli szukasz wyrażenia zwracającego true dla dwóch wartości NULL, możesz użyć:
Jest to przydatne, jeśli chcesz replikować dane z jednej tabeli do drugiej.
źródło
Test równości, na przykład w instrukcji case when klauzula, można zmienić z
do
Jeśli chcę traktować puste miejsca i pusty ciąg jako równe NULL, często używam również testu równości, takiego jak:
źródło