Co w SQL Server oznacza „SET ANSI_NULLS ON”?

92

Definicja mówi:

Gdy SET ANSI_NULLS jest ON, instrukcja SELECT, która używa WHERE nazwa_kolumny = NULL, zwraca zero wierszy, nawet jeśli w kolumnie nazwa_kolumny znajdują się wartości null. Instrukcja SELECT, która używa WHERE nazwa_kolumny <> NULL, zwraca zero wierszy, nawet jeśli w kolumnie nazwa_kolumny znajdują się wartości inne niż null.

Czy to oznacza, że ​​w tym zapytaniu nie zostaną uwzględnione żadne wartości null?

SELECT Region
FROM employees
WHERE Region = @region

A może ANSI_NULLdotyczy tylko zapytań takich jak to (gdzie w WHEREzawiera określone słowo NULL)?

SELECT Region
FROM employees
WHERE Region = NULL
Rodniko
źródło
1
Czy odpowiedzi nie ma już w czwartym akapicie oficjalnej dokumentacji, z której skopiowałeś pierwszy akapit, czyli: -> "SET ANSI_NULLS ON wpływa na porównanie tylko wtedy, gdy jeden z operandów porównania jest zmienną o wartości NULL lub literał NULL. Jeśli obie strony porównania są kolumnami lub wyrażeniami złożonymi, ustawienie nie wpływa na porównanie. "
user1451111

Odpowiedzi:

68

Oznacza to, że nie wiersze zostaną zwrócone, jeśli @regionjest NULL, kiedy jest stosowany w pierwszym przykładzie, nawet jeśli istnieją wiersze w tabeli, gdzie Regionjest NULL.

Kiedy ANSI_NULLSjest włączone (które i tak należy zawsze ustawiać, ponieważ opcja nie włączania tej funkcji zostanie w przyszłości usunięta), każda operacja porównania, w której (przynajmniej) jeden z operandów NULLdaje trzecią wartość logiczną - UNKNOWN( w przeciwieństwie do TRUEi FALSE).

UNKNOWNwartości są propagowane przez dowolne łączące operatory boolowskie, jeśli nie zostały jeszcze określone (np. ANDz FALSEoperandem lub ORz TRUEoperandem) lub przez negacje ( NOT).

WHEREKlauzuli filtrujące zbioru wyników wytwarzanego przez FROMklauzulą, tak, że ogólna wartość WHEREmusi ono być TRUEw rzędzie nie są filtrowane. Tak więc, jeśli UNKNOWNzostanie utworzone przez jakiekolwiek porównanie, spowoduje to odfiltrowanie wiersza.


@ user1227804 za odpowiedź zawiera ten cytat:

Jeśli obie strony porównania są kolumnami lub wyrażeniami złożonymi, ustawienie nie wpływa na porównanie.

od *SET ANSI_NULLS

Nie jestem jednak pewien, o co chodzi, ponieważ jeśli NULLporównuje się dwie kolumny (np. W a JOIN), porównanie nadal się nie udaje:

create table #T1 (
    ID int not null,
    Val1 varchar(10) null
)
insert into #T1(ID,Val1) select 1,null

create table #T2 (
    ID int not null,
    Val1 varchar(10) null
)
insert into #T2(ID,Val1) select 1,null

select * from #T1 t1 inner join #T2 t2 on t1.ID = t2.ID and t1.Val1 = t2.Val1

Powyższe zapytanie zwraca 0 wierszy, podczas gdy:

select * from #T1 t1 inner join #T2 t2 on t1.ID = t2.ID and (t1.Val1 = t2.Val1 or t1.Val1 is null and t2.Val1 is null)

Zwraca jeden wiersz. Więc nawet jeśli oba operandy są kolumnami, NULLnie jest równe NULL. A dokumentacja dla= nie ma nic do powiedzenia na temat operandów:

Kiedy porównujesz dwa NULLwyrażenia, wynik zależy od ANSI_NULLSustawienia:

Jeśli ANSI_NULLSjest ustawiona na ON, wynikiem jest NULL1 , zgodnie z konwencją ANSI, zgodnie z którą NULL(lub nieznana) wartość nie jest równa innej NULLlub nieznanej wartości.

Jeśli ANSI_NULLSjest ustawiona na OFF, wynikiem NULLporównania z NULLjest TRUE.

Porównywanie NULLdo nie- NULLwartości zawsze daje FALSE2 .

Jednak zarówno 1 , jak i 2 są nieprawidłowe - wynik obu porównań jest taki UNKNOWN.


* Tajemnicze znaczenie tego tekstu zostało ostatecznie odkryte wiele lat później. W rzeczywistości oznacza to, że dla tych porównań ustawienie nie ma wpływu i zawsze działa tak, jakby było włączone . Byłoby jaśniejsze, gdyby stwierdził, że SET ANSI_NULLS OFFto ustawienie nie ma żadnego wpływu.

Damien_The_Unbeliever
źródło
1
więc jeśli dobrze cię rozumiem: wpływa to również na wynik wyrażenia „Where Region = @region”, a nie tylko wtedy, gdy napiszę konkretnie „Where Region = null”?
Rodniko
7

Jeśli @Regionnie jest nullwartością (powiedzmy @Region = 'South'), nie zwróci wierszy, w których pole Region ma wartość null, niezależnie od wartości ANSI_NULLS.

ANSI_NULLS będzie miało znaczenie tylko wtedy, gdy wartość @Regionis null, tj. Gdy pierwsze zapytanie stanie się w zasadzie drugim.

W takim przypadku ANSI_NULLS ON nie zwróci żadnych wierszy (ponieważ null = nullzwróci nieznaną wartość logiczną (aka null)), a ANSI_NULLS OFF zwróci wszystkie wiersze, w których pole Region ma wartość null (ponieważ null = nullda true)

SWeko
źródło
6

Jeśli ANSI_NULLS jest ustawione na „ON” i jeśli zastosujemy =, <> na wartość kolumny NULL podczas pisania instrukcji select, to nie zwróci żadnego wyniku.

Przykład

create table #tempTable (sn int, ename varchar(50))

insert into #tempTable
values (1, 'Manoj'), (2, 'Pankaj'), (3, NULL), (4, 'Lokesh'), (5, 'Gopal')

WŁĄCZ ANSI_NULLS

select * from #tempTable where ename is NULL -- (1 row(s) affected)
select * from #tempTable where ename = NULL -- (0 row(s) affected)
select * from #tempTable where ename is not NULL -- (4 row(s) affected)
select * from #tempTable where ename <> NULL -- (0 row(s) affected)

WYŁĄCZ ANSI_NULLS

select * from #tempTable where ename is NULL -- (1 row(s) affected)
select * from #tempTable where ename = NULL -- (1 row(s) affected)
select * from #tempTable where ename is not NULL -- (4 row(s) affected)
select * from #tempTable where ename <> NULL -- (4 row(s) affected)
Pravat Behuria
źródło
2
+1 za to, że jest JEDYNĄ odpowiedzią, która wyraźnie rozróżnia między WHERE X IS NULLi WHERE X = NULLoraz jak ANSI_NULLS wpływa na wynik. Pomimo wysiłków nadmiernie zagorzałych wyborców, TO powinna być akceptowana odpowiedź!
Riegardt Steyn
1
+1 za wyjaśnienie na przykładach, które zawsze będą jaśniejsze i bardziej zwięzłe niż długie zdania.
peter.aryanto
3

WŁĄCZ ANSI_NULLS

IT Zwraca wszystkie wartości, w tym wartości null w tabeli

WYŁĄCZ ANSI_NULLS

kończy się, gdy kolumny zawierają wartości null

Józef Stalin
źródło
2
Co dodatkowo dodaje ta odpowiedź do już podanych odpowiedzi? Uważaj na dodawanie nowych odpowiedzi na stare pytania - Powinny one zawierać rozszerzone wyjaśnienie już opublikowanych rozwiązań lub zapewnić nowy wgląd - Z recenzji
Takarii
1

Myślę, że najważniejsze jest to:

Nigdy nie używaj :

  • @anything = NULL
  • @anything <> NULL
  • @anything != null

Zawsze używaj:

  • @anything IS NULL
  • @anything IS NOT NULL
user369142
źródło
0

Ustawienie ANSI NULLS OFF spowoduje, że porównanie NULL = NULL zwróci wartość true. EG:

        SET ANSI_NULLS OFF
        select * from sys.tables
        where principal_id = Null

zwróci niektóre wyniki, jak pokazano poniżej: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

Chociaż to zapytanie nie zwróci żadnych wyników:

        SET ANSI_NULLS ON 
        select * from sys.tables
        where principal_id = Null
Rozwiązywacz problemów
źródło
0

https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-nulls-transact-sql

Gdy SET ANSI_NULLS jest ON, instrukcja SELECT, która używa WHERE nazwa_kolumny = NULL, zwraca zero wierszy, nawet jeśli w kolumnie nazwa_kolumny znajdują się wartości null. Instrukcja SELECT, która używa WHERE nazwa_kolumny <> NULL, zwraca zero wierszy, nawet jeśli w kolumnie nazwa_kolumny znajdują się wartości inne niż null.

Np

DECLARE @TempVariable VARCHAR(10)
SET @TempVariable = NULL

SET ANSI_NULLS ON
SELECT 'NO ROWS IF SET ANSI_NULLS ON' where    @TempVariable = NULL
-- IF ANSI_NULLS ON , RETURNS ZERO ROWS


SET ANSI_NULLS OFF
SELECT 'THERE WILL BE A ROW IF ANSI_NULLS OFF' where    @TempVariable =NULL
-- IF ANSI_NULLS OFF , THERE WILL BE ROW !
Prasanth VJ
źródło