Dlaczego NULL = NULL ocenia się na false w SQL Server


146

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 NULLi IS NOT NULLsłowa kluczowe to właściwy sposób. Ale dlaczego serwer SQL zachowuje się w ten sposób?


166
Nie mam siostry ani mojego przyjaciela. Jeśli „NULL = NULL”, to mamy wspólną siostrę i dlatego jesteśmy spokrewnieni! :)
Matt Hamilton

11
Od dawna istnieją kontrowersje dotyczące wartości NULL SQL (patrz na przykład: en.wikipedia.org/wiki/Null_%28SQL%29#Controversy i firstsql.com/inulls.htm ). Specyficznym punktem jest tutaj to, że równość jest od dawna ugruntowaną koncepcją matematyczną i SQL ją narusza - równość jest refleksyjna: dla każdego x, x = x. To musi być zawsze prawdą, w przeciwnym razie wprowadza się interpretację równości, która nie jest standardem i oczywistym rezultatem jest zamieszanie.
MaD70

14
W ogóle nie narusza matematyki. Myślę o dwóch liczbach. Nie powiem ci jednak, czym one są. Więc teraz mi powiedz, czy są równi?
Tom H

10
@Matt, nie zgadzam się z twoją analogią. NULL = NULL nie oznaczałoby, że masz wspólną siostrę, oznaczałoby to, że obojgu brakuje siostry.
ponowne wysłanie

5
@ manu08 Nie, obecna implementacja (że NULL nigdy nie jest równa NULL) oznacza, że ​​oboje nie mamy siostry, co było moim celem.
Matt Hamilton,

Odpowiedzi:


205

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 ...

set ansi_nulls off

if null = null
    print 'true'
else
    print 'false'


set ansi_nulls ON

if null = null
    print 'true'
else
    print 'false'

11
x = x jest prawdziwe tylko wtedy, gdy x jest znaną wartością. NULL to tekstowa reprezentacja nieznanej wartości. Jeśli masz dwie nieznane wartości, nie możesz jednoznacznie stwierdzić nic o ich równości. Uważam, że tak samo było przez kilka stuleci.
Dewayne Christensen,

4
Ponieważ jest grudzień, posłużmy się przykładem sezonowym. Pod drzewem mam dwa prezenty. Teraz powiedz mi, czy mam dwa takie same, czy nie.
Dewayne Christensen

5
SQL NULL nie różni się niczym od zmiennoprzecinkowego NaN IEEE, w którym również masz (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.
Pavel Minaev

8
Nie ma tu naruszenia zwrotności, ponieważ NULL nie jest członkiem zbioru wartości (domeny w ujęciu relacyjnym). NULL nie jest wartością . To symbol zastępczy nieznanej wartości.
Pavel Minaev

9
Innymi słowy, każde NULLwyrażenie SQL może być traktowane jako odrębna zmienna matematyczna. Zatem wyrażenie NULL = NULLpowinno być traktowane jako zmienne x = y, gdzie xi ysą 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.
Pavel Minaev

130

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.


4
Nie zgadzam się, że null oznacza „nieznany”. W rzeczywistości oznacza to „brak danych”. Można to wykorzystać do przedstawienia przypadku, w którym informacje nie są znane, ale w rzeczywistości jest bardziej prawdopodobne, że zostanie użyte do wskazania, że ​​coś nie istnieje. Kontynuując przykład: jakie jest drugie imię Franka? On nie ma żadnego (zero). Jakie jest drugie imię Shirley? Ona nie ma żadnego (zero). Czy Frank i Shirley mają to samo drugie imię? Tak? Nie? Nie wiem? Widzę argument „nie” i widzę argument „nie wiem”, ale nie ma prawdziwego argumentu na „tak”, chyba że jesteś zbyt dosłowny.
Richiban,

2
@richiban Nie zgadzam się. Brak wiersza oznacza „brak danych”
Neil McGuigan

1
@NeilMcGuigan To prawda, jeśli w przypadku danych, które mają własną tabelę, ale co z danymi przedstawionymi w kolumnie? Czy nie użyłbyś „null” do oznaczenia faktu, że dane nie istnieją? „Nieznane” to bardzo konkretny powód braku danych.
Richiban,

3
Ale null = nullplony FALSEnie NULL.
slartidan

1
@slartidan Zgadzam się z tobą, jednak jest to niepoprawne
Neil McGuigan

28

Mam nadzieję, że tutaj wyjaśnię swoje stanowisko.

Ta NULL = NULLocena FALSEjest błędna. Hacker i Mister odpowiedzieli poprawnie NULL. Oto dlaczego. Dewayne Christensen napisał do mnie w komentarzu do Scotta Iveya :

Ponieważ jest grudzień, posłużmy się przykładem sezonowym. Pod drzewem mam dwa prezenty. Teraz powiedz mi, czy mam dwa takie same, czy nie.

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 „.. ( falselub null, w zależności od systemu) ..” jest poprawną odpowiedzią - nie jest, tylko NULL 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:

  • logika trójwartościowa (3VL) jest sprzeczna z intuicją (zobacz niezliczone inne pytania na ten temat na Stackoverflow i na innym forum, aby się upewnić);
  • Bazujące na SQL systemy DBMS często nie uwzględniają nawet 3VL, czasami podają błędne odpowiedzi (jak w tym przypadku w oryginalnym plakacie, SQL Server).

Powtarzam więc: SQL nie jest dobrym sposobem na zmuszanie do interpretacji zwrotnej właściwości równości, która stwierdza, że:

for any x, x = x §§ (w prostym języku angielskim: bez względu na wszechświat dyskursu, „rzecz” jest zawsze sobie równa ).

.. w 3VL ( TRUE, FALSE, NULL). Oczekiwanie ludzi byłoby zgodne z 2VL ( TRUE, FALSEco nawet w SQL jest poprawne dla wszystkich innych wartości), tj. x = x Zawsze obliczane do TRUE , 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 : NULLjako 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:

3.4 Arytmetyka i wartości NULL 109
3.5 Konwersja wartości do iz wartości NULL 110
3.5.1 Funkcja NULLIF () 110
6 NULL: brakujące dane w SQL 185
6.4 Porównywanie wartości NULL 190
6.5 NULL i logika 190
6.5.1 NULLS w predykatach podzapytań 191
6.5.2 Standard Rozwiązania SQL 193
6.6 Matematyka i wartości NULL 193
6.7 Funkcje i wartości NULL 193
6.8 NULL i języki hosta 194
6.9 Porady projektowe dla wartości NULL 195
6.9.1 Unikanie wartości NULL w programach nadrzędnych 197
6.10 Uwaga na temat wielu wartości NULL 198
10.1 Predykat IS NULL 241
10.1. 1 Źródła wartości NULL 242
...

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.

NOT NULL Constraint (11)

Najważniejszym ograniczeniem kolumny jest NOT NULL, które zabrania używania wartości NULL w kolumnie. Używaj tego ograniczenia rutynowo i usuwaj je tylko wtedy, gdy masz dobry powód. Pomoże Ci to uniknąć komplikacji związanych z wartościami NULL podczas wykonywania zapytań dotyczących danych.

To nie jest wartość ; jest to znacznik, który utrzymuje miejsce, do którego może trafić wartość.

Znowu ten nonsens „wartość, ale niezupełnie wartość”. Reszta wydaje mi się całkiem rozsądna.

(12)

Krótko mówiąc, wartości NULL powodują wiele nieregularnych funkcji w języku SQL, które omówimy później. Najlepszym rozwiązaniem jest po prostu zapamiętanie sytuacji i zasad dotyczących zerowych wartości, jeśli nie możesz ich uniknąć.

A propos SQL, NULL i Infinite:

(104) ROZDZIAŁ 3: DANE NUMERYCZNE W SQL

SQL nie zaakceptował modelu IEEE dla matematyki z kilku powodów.

...

Gdyby reguły IEEE dla matematyki były dozwolone w języku SQL, potrzebowalibyśmy reguł konwersji typów dla nieskończoności i sposobu reprezentowania nieskończonej dokładnej wartości liczbowej po konwersji. Ludzie mają dość problemów z wartościami NULL, więc nie idźmy tam.

Implementacje SQL nie zdecydowały, co tak naprawdę oznacza NULL w określonych kontekstach:

3.6.2 Funkcje wykładnicze (116)

Problem polega na tym, że logarytmy są niezdefiniowane, gdy (x <= 0). Niektóre implementacje SQL zwracają komunikat o błędzie, inne zwracają wartość NULL i DB2 / 400; wersja 3 wydanie 1 zwróciła jako wynik * NEGINF (skrót od „ujemna nieskończoność”).

Joe Celko cytujący Davida McGoverana i CJ Date:

6 wartości NULL: brakujące dane w języku SQL (185)

W swojej książce A Guide to Sybase and SQL Server David McGoveran i CJ Date powiedzieli: „W opinii tego autora NULL-y, przynajmniej tak jak obecnie zdefiniowano i zaimplementowano w SQL, są o wiele większym kłopotem niż są warte i należy ich unikać; zachowują się bardzo dziwnie i niespójnie i mogą być bogatym źródłem błędów i nieporozumień. (Należy pamiętać, że te komentarze i krytyka dotyczą każdego systemu obsługującego wartości NULL w stylu SQL, a nie tylko SQL Servera) ”.

NULL jako narkomania :

(186/187)

W pozostałej części tej książki będę was zachęcać, abyście ich nie używali , co może wydawać się sprzeczne, ale tak nie jest. Pomyśl o NULL jako leku; używaj go właściwie i działa dla ciebie, ale nadużywaj go i może zepsuć wszystko. Najlepszą zasadą jest unikanie wartości NULL, kiedy możesz, i właściwe ich używanie, gdy musisz.

Moim jedynym zastrzeżeniem jest „właściwe ich używanie”, co źle współgra z określonymi zachowaniami implementacyjnymi.

6.5.1 NULLS w predykatach podzapytań (191/192)

Ludzie zapominają, że podzapytanie często ukrywa porównanie z wartością NULL. Rozważ te dwie tabele:

...

Wynik będzie pusty. Jest to sprzeczne z intuicją , ale poprawne.

(separator)

6.5.2 Standardowe rozwiązania SQL (193)

SQL-92 rozwiązał niektóre problemy z logiką trójwartościową (3VL), dodając nowy predykat postaci:

<warunek wyszukiwania> JEST [NIE] PRAWDA | FALSE | NIEZNANY

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 :

  • Nie używaj słowa kluczowego UNKNOWN w żadnym kontekście.

Przeczytaj „ASIDE” w UNKNOWN, do której link znajduje się poniżej.

6.8 NULL i języki hosta (194)

Powinieneś jednak wiedzieć, jak obsługiwane są wartości NULL, gdy muszą zostać przekazane do programu hosta. Żaden standardowy język hosta, dla którego zdefiniowano osadzanie, nie obsługuje wartości NULL, co jest kolejnym dobrym powodem, aby unikać ich używania w schemacie bazy danych.

(separator)

6.9 Wskazówki projektowe dla NULL (195)

Dobrym pomysłem jest zadeklarowanie wszystkich tabel podstawowych z ograniczeniami NOT NULL we wszystkich kolumnach, gdy tylko jest to możliwe. Wartości NULL dezorientują ludzi, którzy nie znają języka SQL, a wartości NULL są drogie.

Zarzut: wartości NULL dezorientują nawet osoby dobrze znające SQL, patrz poniżej.

(195)

Należy unikać wartości NULL w kluczach obcych. SQL dopuszcza tę relację „korzyści z wątpliwości”, ale może spowodować utratę informacji w zapytaniach, które obejmują łączenie. Na przykład, biorąc pod uwagę kod numeru części w magazynie, który jest określany jako KLUCZ OBCY w tabeli Zamówienia, będziesz mieć problemy z wyświetleniem listy części, które mają wartość NULL. To jest obowiązkowy związek; nie możesz zamówić części, która nie istnieje.

(separator)

6.9.1 Unikanie wartości NULL w programach głównych (197)

Możesz uniknąć umieszczania wartości NULL w bazie danych z programów głównych z pewną dyscypliną programowania.

...

  1. Określ wpływ brakujących danych na programowanie i raportowanie: Kolumny liczbowe z wartościami NULL stanowią problem, ponieważ zapytania korzystające z funkcji agregujących mogą dawać mylące wyniki.

(separator)

(227)

SUMA () pustego zestawu ma zawsze wartość NULL. Jednym z najczęstszych błędów programistycznych popełnianych podczas korzystania z tej sztuczki jest napisanie zapytania, które może zwrócić więcej niż jeden wiersz. Gdybyś o tym nie pomyślał, mógłbyś napisać ostatni przykład jako: ...

(separator)

10.1.1 Źródła wartości NULL (242)

Należy pamiętać, gdzie mogą wystąpić wartości NULL. Są czymś więcej niż tylko możliwą wartością w kolumnie . Funkcje agregujące na pustych zbiorach, OUTER JOIN, wyrażeniach arytmetycznych z wartościami NULL i operatorach OLAP zwracają wartości NULL. Konstrukcje te często pojawiają się jako kolumny w WIDOKACH.

(separator)

(301)

Inny problem z wartościami NULL występuje podczas próby konwersji predykatów IN na predykaty EXISTS.

(separator)

16.3 WSZYSTKIE funkcje predykatów i ekstremów (313)

Na początku jest sprzeczne z intuicją, że te dwa predykaty nie są takie same w SQL:

...

Ale musisz pamiętać o regułach dla funkcji extrema - usuwają one wszystkie wartości NULL przed zwróceniem większej lub najmniejszej wartości. Predykat ALL nie usuwa wartości NULL, więc można je uzyskać w wynikach.

(separator)

(315)

Jednak definicja w standardzie jest sformułowana w sposób negatywny, aby wartości NULL zostały uwzględnione w wątpliwościach. ...

Jak widać, dobrym pomysłem jest unikanie wartości NULL w ograniczeniach UNIQUE.

Omówienie GROUP BY:

Wartości NULL są traktowane tak, jakby wszystkie były sobie równe i tworzą własną grupę. Każda grupa jest następnie redukowana do jednego wiersza w nowej tabeli wynikowej, która zastępuje starą.

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:

ORDER BY i wartości NULL (329)

Czy wartość klucza sortowania, która wynosi NULL, jest uważana za większą, czy mniejszą od wartości innej niż NULL, jest definiowana przez implementację, ale ...

... Istnieją produkty SQL, które to robią.

W marcu 1999 roku Chris Farrar zadał pytanie jednemu ze swoich programistów, które skłoniło go do zbadania części standardu SQL, o której myślałem, że rozumiem . Chris znalazł pewne różnice między ogólnym zrozumieniem a faktycznym sformułowaniem specyfikacji .

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):

10.3 Praktyczne implikacje

10.3.1 wartości NULL języka SQL

... SQL cierpi na problemy tkwiące w 3VL, a także na wiele dziwactw, komplikacji, sprzecznych z intuicją i oczywistych błędów [10, 11]; wśród nich są:

  • Funkcje agregujące (np. SUMA (), AVG ()) ignorują wartości NULL (z wyjątkiem COUNT ()).
  • Wyrażenie skalarne w tabeli bez wierszy przyjmuje niepoprawną wartość NULL zamiast 0.
  • Wyrażenie „NULL = NULL” przyjmuje wartość NULL, ale w rzeczywistości jest niepoprawne w języku SQL; jednak ORDER BY traktuje wartości NULL jako równe (cokolwiek poprzedzają lub następują po „zwykłych” wartościach, pozostawione jest dostawcy DBMS).
  • Wyrażenie „x NIE JEST NULL” nie jest równe „NIE (x JEST NULL)”, jak w przypadku 2VL.

...

Wszystkie komercyjnie wdrażane dialekty SQL są zgodne z tym podejściem 3VL, a zatem nie tylko wykazują te problemy, ale także mają sprecyzowane problemy z implementacją, które różnią się w zależności od produktu .


4
„I o to mi chodziło: NULL jako wartość jest„ dziwną bestią ”. - to dlatego, że NULLnie jest wartością.
Pavel Minaev

1
Ponadto SQL Server nie daje (NULL = NULL) -> FALSE. Cytując dokumentację dla ANSI_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.”
Pavel Minaev

@Pavel Minaev: a) i dlaczego PRAWDA jest lepsza niż FAŁSZ? b) Jeśli nie jest wartością, dlaczego jest przypisywana jako część wartości zmiennych?
MaD70

1
>> Ponieważ jest grudzień, posłużmy się przykładem sezonowym. Pod drzewem mam dwa prezenty. Teraz powiedz mi, czy mam dwa takie same, czy nie. ..... tak, zrobiłeś to, ponieważ masz dwie rzeczy i jeśli o to chodzi w tej chwili , w zakresie twojej obecnej wiedzy, są one dokładnie takie same dla ciebie
Brad Thomas,

3
null = null powinno być prawdziwe. zerowa jest dobrze zdefiniowana wartość, która może reprezentować o nieznanej wartości, ale może również reprezentować na brak podanej wartości. To programista powinien zdecydować, co reprezentuje null, ale samo null jest absolutnie wartością, a null jest null = null. Każda inna implementacja jest skazana na katastrofę, ponieważ wstawiasz logikę trójskładnikową do predykatów, które są zasadniczo logiczne. Jestem ZADOWOLONY, że to staje się trwałe w ustawieniach serwera SQL. OFF OFF OFF z nim.
Triynko


9

To, że nie wiesz, czym są dwie rzeczy, nie oznacza, że ​​są równe. Jeśli NULLmyślisz o „NULL” (ciąg znaków), prawdopodobnie potrzebujesz innego testu równości, takiego jak IS DISTINCT FROMORAZ PostgresqlaIS NOT DISTINCT FROM

Z dokumentacji PostgreSQL na temat „Funkcje porównawcze i operatory”

wyrażenie IS DISTINCT FROMwyrażenie

wyrażenie IS NOT DISTINCT FROMwyrażenie

W przypadku danych wejściowych innych niż null IS DISTINCT FROMdziała tak samo, jak <>operator. Jeśli jednak oba dane wejściowe mają wartość null, zwraca wartość false, a jeśli tylko jedno wejście ma wartość null, zwraca wartość true. Podobnie IS NOT DISTINCT FROMdziała tak samo, jak =dla danych wejściowych innych niż null, ale zwraca wartość true, gdy oba dane wejściowe mają wartość null, i false, gdy tylko jedno wejście ma wartość null. W związku z tym konstrukcje te skutecznie działają tak, jakby wartość null była normalną wartością danych, a nie „nieznaną”.


5

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 NULLw SQL jest błędna (implementacja SQL Servera komplikuje sprawę jeszcze bardziej ze względu na swoją ANSI_NULLSopcję).

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 NULLdziała w SQL:

NULL= NULLszacuje się do UNKNOWN.

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 UNKNOWNjest traktowana inaczej odpowiednio w SQL DML i SQL DDL.

W SQL DML UNKNOWNpowoduje usuwanie wierszy z zestawu wyników.

Na przykład:

CREATE TABLE MyTable
(
 key_col INTEGER NOT NULL UNIQUE, 
 data_col INTEGER
 CHECK (data_col = 55)
);

INSERT INTO MyTable (key_col, data_col)
   VALUES (1, NULL);

INSERTUda do tego wiersza, choć CHECKstan postanawia NULL = NULL. Jest to określone w standardzie SQL-92 („ANSI”):

11.6 Definicja ograniczeń tabeli

3)

Jeśli ograniczenie tabeli jest definicją ograniczenia sprawdzającego, niech SC będzie warunkiem wyszukiwania bezpośrednio zawartym w definicji ograniczenia sprawdzającego, a T będzie nazwą tabeli zawartą w odpowiednim deskryptorze ograniczenia tabeli; ograniczenie tabeli nie jest spełnione wtedy i tylko wtedy, gdy

ISTNIEJE (WYBIERZ * Z T GDZIE NIE (SC))

jest prawdziwy.

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 UNKNOWNi pozwolenia na przejście.

W SQL DML reguła WHEREklauzuli jest znacznie łatwiejsza do przestrzegania:

Warunek wyszukiwania jest stosowany do każdego wiersza T. Wynikiem klauzuli where jest tabela tych wierszy T, dla których warunek wyszukiwania jest prawdziwy.

W zwykłym języku angielskim wiersze, których wynikiem jest wartość, UNKNOWNsą usuwane z zestawu wyników.


5

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

where (value=@param Or @param is null) And id=@anotherParam

i

  • wartość = 1
  • @param ma wartość null
  • id = 123
  • @ anotherParam = 123

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.


4

Ponieważ NULLoznacza „nieznaną wartość” i dwie nieznane wartości nie mogą być równe.

Jeśli więc zgodnie z naszą logiką NULLnr 1 równa się NULLnr 2, to musimy jakoś to powiedzieć:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

gdzie znana wartość -1nr 1 jest równa -1nr 2


nullParam1 = -1a nullParam2 =NULLi katastrofa ISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
lotnicza

4

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 NULLskł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.


1
Wydaje się, że każdy krzyczy „NULL jest nieznany”, a następnie usprawiedliwia to zachowanie. Tak, jeśli to przesłanka, to 3VL może być odpowiedzią. Ale w prawie wszystkich bazach danych, nad którymi pracuję, NULL oznacza nieobecność. Przepraszam, że gubisz się w dziczy @AlexDev
John Rees

3

NULL nie jest niczym, nawet sobie. Moim osobistym sposobem zrozumienia zachowania NULL jest unikanie używania go w jak największym stopniu :).


1
równie dobrze może równać się wszystkiemu, jak to jest w przypadku połączeń lewych / prawych / zewnętrznych ...
Miguel Ventura,

5
Co za głupia bezproduktywna odpowiedź. To samo można powiedzieć dzieciom ze szkoły podstawowej o algebrze, ale bez zrozumienia tego, co próbuje rozwiązać, okazałoby się po prostu głupie, co też się stało.
Evan Carroll,

2
@Evan: Właściwie unikanie NULL to rozsądne rozwiązanie. Logika trójwartościowa nie jest kontrowersyjna i wiele osób uważa, że ​​SQL byłby lepszy bez wartości NULL i całej (koniecznej) złożoności, która się z tym wiąże.
sleske

3
„Wiele osób” to dziwaczne słowo, a „nie niekontrowersyjne” to sposób na ukrycie prostszego „kontrowersyjnego”, którego 3VL nie jest.
Evan Carroll,

„NULL nie jest niczym, nawet sobie”. zgodnie z tą logiką, <somevalue>! = NULL powinno zwrócić prawdę. Jednak w dziwnym świecie SQL jest to fałsz.
Tom Lint

3

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


3

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.


3

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:

= operator NULL   true   false 
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true

and op     NULL   true   false 
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false

or op      NULL   true   false 
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false

Ale pytanie nie dotyczy 3VL (logika trójwartościowa), dotyczy refleksyjnej właściwości równości.
MaD70

Mówiąc dokładniej, jak wyszczególniłem w końcu w mojej odpowiedzi, pojawiają się problemy, gdy równość jest interpretowana w 3VL, tak że refleksyjna właściwość równości nie zawsze jest uznawana za prawdziwą.
MaD70

1

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

SET ANSI_NULLS off
if null=null
print 1
else 
print 2
set ansi_nulls on
if null=null
print 1
else 
print 2

2
To wszelkiego rodzaju nie . Świat ma definicję null, naucz się go rozumieć lub po prostu zmodyfikuj tabelę, aby zawierała typy int i zaktualizuj kolumny.
Evan Carroll,

3
Naprawdę nie polecałem wyłączania ANSI_NULLS. Dowiedziałem się o ANSI_NULLS na własnej skórze. Ale zawsze dobrze jest znać wszystkie dostępne opcje, zwłaszcza gdy natrafisz na linię, która mówi Where SomeId = null Jak nadać sens tej linii, nie wiedząc o ANSI_NULLS. Tak jak ja to wyglądam, mój post się przydał .. :)
ps.

1

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 NULLopcji 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, że NULL = NULLnie jest prawdą.

Potrzeba jest matka wynalazku.


0

To tylko dodatek do innych wspaniałych odpowiedzi:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.

OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.

NOT: The result of not unknown is unknown

0

Jeśli szukasz wyrażenia zwracającego true dla dwóch wartości NULL, możesz użyć:

SELECT 1 
WHERE EXISTS (
    SELECT NULL
    INTERSECT
    SELECT NULL
)

Jest to przydatne, jeśli chcesz replikować dane z jednej tabeli do drugiej.


0

Test równości, na przykład w instrukcji case when klauzula, można zmienić z

XYZ = NULL 

do

XYZ IS NULL

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:

(NULLIF(ltrim( XYZ ),'') IS NULL)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.