Nie równy <>! = Operator na NULL


271

Czy ktoś mógłby wyjaśnić następujące zachowanie w SQL?

SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)

Odpowiedzi:


309

<>to Standard SQL-92; !=jest jego odpowiednikiem. Oba oceniają wartości, które NULLnie są - NULLjest symbolem zastępczym, który mówi, że nie ma wartości.

Dlatego możesz używać IS NULL/ IS NOT NULLjako predykatów tylko w takich sytuacjach.

To zachowanie nie jest specyficzne dla SQL Server. Wszystkie dialekty SQL zgodne ze standardami działają w ten sam sposób.

Uwaga : Aby porównać, jeśli twoja wartość nie jest równa null , użyj IS NOT NULL, natomiast do porównania z wartością inną niż null , użyj <> 'YOUR_VALUE'. Nie mogę powiedzieć, czy moja wartość jest równa NULL, ale mogę powiedzieć, czy moja wartość to NULL, czy NIE NULL. Mogę porównać, jeśli moja wartość jest inna niż NULL.


4
Właściwie uważam, że <>tak jest w specyfikacji 92, ale większość dostawców obsługuje !=i / lub jest uwzględniona w późniejszej specyfikacji, np. 99 lub 03.
Thomas

2
@Thomas: Oracle nie wspierał !=aż ~ 9i, jak rozumiem, co przyniosło wiele składni ANSI-92. Wierzę, że MySQL jest podobny, zaczynając wsparcie w 4.x.
OMG Kucyki

Wydaje się to sugerować, że !=mógł zostać włączony do późniejszej specyfikacji jako alternatywa dla <>. Nie mam nowych specyfikacji, więc nie mogę być tego pewien.
Thomas

2
Jest wynikiem WHERE MyColumn != NULLlub WHERE MyColumn = NULLdeterministyczny? Innymi słowy, czy gwarantuje, że zawsze zwróci 0 wierszy, bez względu na MyColumnto, czy w bazie danych jest dopuszczalna wartość null?
Slauma,

11
Należy również zauważyć, że ponieważ !=tylko ocenia wartości, zrobienie czegoś podobnego WHERE MyColumn != 'somevalue'nie zwróci rekordów NULL.
jsumrall

88

Wartość NULL nie ma wartości, dlatego nie można jej porównywać za pomocą operatorów wartości skalarnych.

Innymi słowy, żadna wartość nigdy nie może być równa (lub nie być równa) NULL, ponieważ NULL nie ma żadnej wartości.

Dlatego SQL ma specjalne predykaty IS NULL i IS NOT NULL do obsługi NULL.


3
+1. I w przeciwieństwie do instrukcji OP nie jest to „Microsoft SQL”. Logika trójdzielna jest zdefiniowana w standardzie SQL, a MS w tym punkcie przestrzega normy.
TomTom

6
Nie sugerowałem, że jest to zachowanie wyłącznie Microsoft. Po prostu stwierdziłem, że zaobserwowałem to na Microsoft SQL Server.
Maxim Gershkovich

13
Czy poza interesami są jakieś sytuacje, w których to (oczekiwane) zachowanie jest przydatne? Wydaje mi się, że 'a' != nullNIE zwracanie wartości ( true/ 1) jest sprzeczne z intuicją i od czasu do czasu mnie łapie! Myślałem, że „pewna wartość w porównaniu do żadnej wartości” zawsze będzie „nie równa”, ale może to tylko ja?!?
DarthPablo

1
Myślę, że interesujące jest to, że ludzie opisują NULL jako „ bez wartości ”. Podobnie jest z powiedzeniem, że liczba 1 „ma wartość”, kiedy faktycznie jest wartością. Ale NULL reprezentuje brak wartości ..
systemaddict

Jako obejście ręczne często SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'można przypisać stałą, jeśli jest to NULL, pod warunkiem, że podasz odpowiedni typ danych dla wartości wartownika x (w tym przypadku ciąg / char). Jest to składnia TSQL, ale Oracle i inne silniki mają podobne funkcje.
systemaddict

26

Należy pamiętać, że takie zachowanie jest zachowaniem domyślnym (ANSI).

Jeśli ty:

 SET ANSI_NULLS OFF

http://msdn.microsoft.com/en-us/library/ms188048.aspx

Otrzymasz różne wyniki.

SET ANSI_NULLS OFF najwyraźniej odejdzie w przyszłości ...


8
+1 ... za wcześnie. Kiedy mogę uzyskać „zduplikowane” wartości NULL w indeksie? :(

Możesz uzyskać zduplikowane wartości NULL w indeksie SQL Server, dodając klauzulę WHERE w indeksie filtrowanym (np. create unique index UK_MyTable on MyTable (Column) where Column is not null): Msdn.microsoft.com/en-us/library/cc280372.aspx
Anthony Mills

3
Uwaga z dokumentów: Kiedy SET ANSI_NULLSjest wyłączona, operatory porównania równe (=) i nierówne (<>) nie są zgodne ze standardem ISO. Instrukcja SELECT, która używa, WHERE column_name = NULLzwraca wiersze o wartości null w kolumnie nazwa_kolumny. WHERE column_name <> NULLUżyta instrukcja SELECT zwraca wiersze, które mają niepuste wartości w kolumnie. Ponadto instrukcja SELECT, która używa, WHERE column_name <> XYZ_valuezwraca wszystkie wiersze, które nie są wartościami XYZ i które nie mają wartości NULL. IMHO, to ostatnie stwierdzenie wydaje się trochę dziwne, ponieważ wyklucza wartości zerowe z wyników!
DarthPablo

4
Ważna uwaga z dokumentu msdn : W przyszłej wersji SQL Server [nowszej niż 2014] ANSI_NULLS zawsze będzie WŁĄCZONY, a wszelkie aplikacje, które jawnie
Otiel

7

W SQL wszystko oceniasz / obliczasz z NULLwynikami w NIEZNANY

Dlatego SELECT * FROM MyTable WHERE MyColumn != NULLlub SELECT * FROM MyTable WHERE MyColumn <> NULLdaje 0 wyników.

Aby zapewnić sprawdzanie NULLwartości, zapewniona jest funkcja isNull.

Ponadto możesz użyć ISoperatora, tak jak w trzecim zapytaniu.

Mam nadzieję że to pomoże.


„W SQL wszystko, co oceniasz / obliczasz z wynikami NULL na„ NULL ”” - niepoprawne. Masz na myśli wynik NIEZNANY.
poniedziałek

@ MahendraLiya nie jest dostępna funkcja isNull w celu sprawdzenia wartości NULLS, ale „ Zastępuje NULL określoną wartością zastępczą ”. Powinieneś użyć IS NULL lub IS NOT NULL zamiast ISNULL, co jest inną rzeczą.
Odwrócony inżynier


6

Używamy

SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';

aby zwrócić wszystkie wiersze, w których MyColumn ma wartość NULL lub wszystkie wiersze, w których MyColumn jest pustym ciągiem. Dla wielu „użytkowników końcowych” kwestia NULL vs. pusty ciąg znaków jest rozróżnieniem bez potrzeby i zamieszania.


5

Po prostu nie widzę funkcjonalnego i bezproblemowego powodu, dla którego wartości zerowe nie są porównywalne z innymi wartościami lub innymi wartościami zerowymi, ponieważ możemy je wyraźnie porównać i powiedzieć, że są takie same lub nie w naszym kontekście. To jest zabawne. Właśnie z powodu pewnych logicznych wniosków i konsekwencji musimy stale się tym przejmować. Nie działa, uczyń go bardziej funkcjonalnym i pozostaw filozofom i naukowcom do stwierdzenia, czy jest spójny czy nie, i czy zawiera „uniwersalną logikę”. :) Ktoś może powiedzieć, że to z powodu indeksów lub czegoś innego, wątpię, aby te rzeczy nie mogły być obsługiwane przez wartości zerowe takie same jak wartości. To tak samo, jak porównywanie dwóch pustych kieliszków, jedna to kieliszek do wina, a druga to kufel do piwa, nie porównujemy typów obiektów, ale wartości, które zawierają, tak samo jak można porównać int i varchar, z null it ” jeszcze łatwiej, to nic i to, co łączy ze sobą dwie nicość, są takie same, wyraźnie porównywalne przeze mnie i przez wszystkich innych, którzy piszą sql, ponieważ ciągle łamiemy tę logikę, porównując je w dziwny sposób ze względu na niektóre standardy ANSI. Dlaczego nie skorzystać z mocy komputera, aby zrobić to za nas i wątpię, że spowolniłoby to wszystko, gdyby wszystko związane z tym zostało skonstruowane z myślą o tym. „To nie jest zero, to nic”, to nie jest jabłko, to jest apfel, daj spokój ... Funkcjonalnie jest twoim przyjacielem i jest tu również logika. Ostatecznie jedyną rzeczą, która ma znaczenie, jest funkcjonalność i używanie zer w ten sposób zapewnia mniej więcej funkcjonalność i łatwość użycia. Czy to jest bardziej przydatne? ponieważ ciągle łamiemy tę logikę, porównując je w dziwny sposób z powodu niektórych standardów ANSI. Dlaczego nie skorzystać z mocy komputera, aby zrobić to za nas i wątpię, że spowolniłoby to wszystko, gdyby wszystko związane z tym zostało skonstruowane z myślą o tym. „To nie jest zero, to nic”, to nie jest jabłko, to jest apfel, daj spokój ... Funkcjonalnie jest twoim przyjacielem i jest tu również logika. Ostatecznie jedyną rzeczą, która ma znaczenie, jest funkcjonalność i używanie zer w ten sposób zapewnia mniej więcej funkcjonalność i łatwość użycia. Czy to jest bardziej przydatne? ponieważ ciągle łamiemy tę logikę, porównując je w dziwny sposób z powodu niektórych standardów ANSI. Dlaczego nie skorzystać z mocy komputera, aby zrobić to za nas i wątpię, że spowolniłoby to wszystko, gdyby wszystko związane z tym zostało skonstruowane z myślą o tym. „To nie jest zero, to nic”, to nie jest jabłko, to jest apfel, daj spokój ... Funkcjonalnie jest twoim przyjacielem i jest tu również logika. Ostatecznie jedyną rzeczą, która ma znaczenie, jest funkcjonalność i używanie zer w ten sposób zapewnia mniej więcej funkcjonalność i łatwość użycia. Czy to jest bardziej przydatne? to nie jabłko, to apfel, daj spokój ... Funkcjonalnie jest twoim przyjacielem i tutaj też jest logika. Ostatecznie jedyną rzeczą, która ma znaczenie, jest funkcjonalność i używanie zer w ten sposób zapewnia mniej więcej funkcjonalność i łatwość użycia. Czy to jest bardziej przydatne? to nie jabłko, to apfel, daj spokój ... Funkcjonalnie jest twoim przyjacielem i tutaj też jest logika. Ostatecznie jedyną rzeczą, która ma znaczenie, jest funkcjonalność i używanie zer w ten sposób zapewnia mniej więcej funkcjonalność i łatwość użycia. Czy to jest bardziej przydatne?

Rozważ ten kod:

SELECT CASE WHEN NOT (1 = null or (1 is null and null is null)) THEN 1 ELSE 0 end

Ilu z was wie, co zwróci ten kod? Z lub bez NOT zwraca 0. Dla mnie to nie działa i jest mylące. W c # wszystko jest tak, jak powinno być, operacje porównywania zwracają wartość, logicznie to też tworzy wartość, ponieważ jeśli nie, nie ma nic do porównania (oprócz. Nic :)). Po prostu „powiedzieli”: cokolwiek w porównaniu do null „zwraca” 0, co stwarza wiele obejść i bólów głowy.

Oto kod, który mnie tu przyprowadził:

where a != b OR (a is null and b IS not null) OR (a IS not null and b IS null)

Muszę tylko porównać, jeśli dwa pola (gdzie) mają różne wartości, mógłbym użyć funkcji, ale ...


4

NULL Nie można porównać do żadnej wartości za pomocą operatorów porównania. NULL = NULL jest fałszem. Null nie jest wartością. Operator IS jest specjalnie zaprojektowany do obsługi porównań NULL.


5
Zawsze lubiłem zdezorientowanych ludzi, kiedy czasami używam tego, null = nullco można wykorzystać 1=0w zapytaniu ad hoc. A jeśli narzekają, zmieniam na null != null:)
SWeko

8
„NULL = NULL jest fałszem” Tak nie jest. NULL = NULL ocenia na nieznany i nie fałszywy.
nvogel

@dportas tak jest, ale miałem na myśli, że w warunkowym przypadku nie będzie to oceniane jako prawda.
Vincent Ramdhanie

@ VincentRamdhanie ani jako fałsz; tak naprawdę, w postgresie będzie to oceniane jako NULL
Pere

2

Stare pytanie, ale poniższe mogą zawierać więcej szczegółów.

nulloznacza brak wartości lub nieznaną wartość. Nie określa, dlaczego nie ma wartości, co może prowadzić do niejasności.

Załóżmy, że uruchamiasz takie zapytanie:

SELECT *
FROM orders
WHERE delivered=ordered;

oznacza to, że szukasz wierszy, w których daty orderedi deliveredsą takie same.

Czego można się spodziewać, gdy jedna lub obie kolumny są puste?

Ponieważ co najmniej jedna z dat jest nieznana, nie można oczekiwać, że obie daty będą takie same. Jest tak również w przypadku, gdy oba daty są nieznane: jak mogą być takie same, jeśli nawet nie wiemy, jakie są?

Z tego powodu każde wyrażenie traktowane nulljako wartość musi zawieść. W takim przypadku nie będzie pasować. Dzieje się tak również wtedy, gdy spróbujesz:

SELECT *
FROM orders
WHERE delivered<>ordered;

Ponownie, jak możemy powiedzieć, że dwie wartości nie są takie same, jeśli nie wiemy, czym one są.

SQL ma specyficzny test na brakujące wartości:

IS NULL

W szczególności nie porównuje wartości, ale szuka brakujących wartości.

Wreszcie, jeśli chodzi o !=operatora, o ile mi wiadomo, nie jest on faktycznie objęty żadnym ze standardów, ale jest bardzo szeroko wspierany. Zostało dodane, aby programiści z niektórych języków czuli się bardziej jak w domu. Szczerze mówiąc, jeśli programista ma trudności z zapamiętaniem używanego języka, zaczyna się źle.


Jest to ta sama „bezsensowna” logika, którą @Hove opisuje w swojej odpowiedzi. Prawda jest taka, że ​​w tym kontekście nie ma potrzeby tych dodatkowych akcesoriów; można łatwo założyć, że gdy porównujemy coś do a, NULLmamy na myśli, że porównujemy wartość z „posiadaniem NULLwartości”, a nie z wartością „nieokreślonej wartości, jaką NULLma podkład ”? ale której nie wiemy ”, o którym oczywiście nigdy nie będziemy wiedzieć. To naprawdę by to ułatwiło.
Pere

@Pere nie powiedziałbym, że jest to ściśle „nonsensowne” i nie jestem pewien, czy pisanie IS NULLjest o wiele bardziej uciążliwe niż pisanie = NULL. Myślę, że byłoby bardziej spójne, gdyby WHERE columnA = columnBmiało taką samą interpretację WHERE columnA = NULL, niż traktować tę ostatnią jako szczególny przypadek. Pamiętaj, że NULLto nie jest wartość. W języków programowania, gdzie to jest uzasadnione, aby przetestować variable == nullto dlatego, że nullma inne znaczenie; nie reprezentuje czegoś nieznanego, ale celowe resetowanie wartości. Nie w przypadku SQL.
Manngo,

Dlatego umieszczam to między cudzysłowami, @Mangoo;) (a także „logiką”). Nie złość się na mnie; Mówiłem o „rozumowaniu” ANSI, a nie o twoich wyjaśnieniach. Zgadzam się, że w twoim najnowszym przykładzie nie ma narzutu między IS NULLAND =NULL. Ale spójrz na ostatni Hover. Mam dość ciągłego doświadczania tego, że muszę robić mnóstwo niepotrzebnych? dodatkowe sprawdzanie ...
Pere

1

Chciałbym zasugerować ten kod, który stworzyłem, aby sprawdzić, czy nastąpiła zmiana wartości, ibędąc nową wartością i dbędąc starą (chociaż kolejność nie ma znaczenia). Z tego powodu zmiana z wartości na null lub odwrotnie jest zmianą, ale z null na null nie jest (oczywiście, od wartości do innej wartości jest zmianą, ale od wartości do tej samej nie jest).

CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
    @i sql_variant,
    @d sql_variant
)
RETURNS bit
AS
BEGIN
    DECLARE @in bit = 0, @dn bit = 0
    if @i is null set @in = 1
    if @d is null set @dn = 1

    if @in <> @dn
        return 0

    if @in = 1 and @dn = 1
        return 1

    if @in = 0 and @dn = 0 and @i = @d
        return 1

    return 0

END

Aby skorzystać z tej funkcji, możesz

declare @tmp table (a int, b int)
insert into @tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)

---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from @tmp

---- where equal ----
select *,'equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 1

---- where not equal ----
select *,'not equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 0

Wyniki są następujące:

---- in select ----
a   b   =
1   1   1
1   2   0
1   NULL    0
NULL    1   0
NULL    NULL    1

---- where equal ----
1   1   equal
NULL    NULL    equal

---- where not equal ----
1   2   not equal
1   NULL    not equal
NULL    1   not equal

Zastosowanie sql_variant sprawia, że ​​jest on kompatybilny z różnymi typami


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.