Что означает «SET ANSI_NULLS ON» в SQL Server?

92

В определении говорится:

Когда для SET ANSI_NULLS установлено значение ON, инструкция SELECT, использующая WHERE column_name = NULL, возвращает нулевые строки, даже если в столбце имя_столбца есть нулевые значения. Оператор SELECT, использующий WHERE column_name <> NULL, возвращает нулевые строки, даже если в column_name есть ненулевые значения.

Означает ли это, что в этот запрос не будут включены нули?

SELECT Region
FROM employees
WHERE Region = @region

Или это ANSI_NULLкасается только таких запросов (где WHEREесть конкретное слово NULL)?

SELECT Region
FROM employees
WHERE Region = NULL
Роднико
источник
1
Нет ли ответа в 4-м параграфе официальной документации, из которой вы скопировали 1-й параграф, а именно: -> «SET ANSI_NULLS ON влияет на сравнение только в том случае, если один из операндов сравнения является переменной, имеющей значение NULL. или буквальный NULL. Если обе стороны сравнения являются столбцами или составными выражениями, параметр не влияет на сравнение ».
user1451111

Ответы:

68

Это означает , что ни одна строка не будет возвращена , если @regionесть NULL, при использовании в первом примере, даже если есть строки в таблице , где RegionнаходитсяNULL .

Когда ANSI_NULLSон включен (который вы всегда должны устанавливать в любом случае, так как опция, чтобы не включать его, будет удалена в будущем), любая операция сравнения, в которой (по крайней мере) один из операндов, NULLдает третье логическое значение - UNKNOWN( в отличие от TRUEи FALSE).

UNKNOWNзначения распространяются через любые комбинирующие логические операторы, если они еще не определены (например, ANDс FALSEоперандом или ORс TRUEоперандом) или отрицаниями ( NOT).

Предложение WHEREиспользуется для фильтрации набора результатов, созданного FROMпредложением, так что общее значение WHEREпредложения должно быть TRUEтаким, чтобы строка не фильтровалась. Таким образом, если в UNKNOWNрезультате какого-либо сравнения будет получено an, строка будет отфильтрована.


@ user1227804 в ответ включает эту цитату:

Если обе стороны сравнения - столбцы или составные выражения, параметр не влияет на сравнение.

от *SET ANSI_NULLS

Однако я не уверен, какой смысл он пытается донести, поскольку при NULLсравнении двух столбцов (например, в a JOIN) сравнение все равно не выполняется:

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

Вышеупомянутый запрос возвращает 0 строк, тогда как:

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)

Возвращает одну строку. Таким образом, даже если оба операнда являются столбцами, NULLне равно NULL. А в документации по= операндам ничего не говорится:

Когда вы сравниваете два NULLвыражения, результат зависит от ANSI_NULLSнастройки:

Если ANSI_NULLSустановлено значение ON, результатом будет NULL1 , в соответствии с соглашением ANSI о том, что NULL(или неизвестное) значение не равно другому NULLили неизвестному значению.

Если ANSI_NULLSустановлено значение OFF, результат NULLсравнения с NULLравен TRUE.

Сравнение NULLс не- NULLзначением всегда приводит к FALSE2 .

Однако и 1, и 2 неверны - результат обоих сравнений UNKNOWN.


* Загадочный смысл этого текста был наконец открыт много лет спустя. На самом деле это означает, что для этих сравнений параметр не имеет никакого эффекта и всегда действует так, как если бы параметр был включен . Было бы яснее, если бы было указано, что SET ANSI_NULLS OFFэто настройка, которая не имеет никакого влияния.

Damien_The_Unbeliever
источник
1
так что, если я правильно вас понял: это влияет и на результат фразы «Где регион = @region», а не только тогда, когда я пишу конкретно «Где регион = null»?
Rodniko
7

Если @Regionне является nullзначением (допустим @Region = 'South'), он не будет возвращать строки, в которых поле «Регион» имеет значение NULL, независимо от значения ANSI_NULLS.

ANSI_NULLS будет иметь значение только тогда, когда значение @Regionравно null, то есть когда ваш первый запрос по существу становится вторым.

В этом случае ANSI_NULLS ON не будет возвращать никаких строк (потому null = nullчто даст неизвестное логическое значение (aka null)), а ANSI_NULLS OFF вернет любые строки, в которых поле Region имеет значение NULL (потому что null = nullбудет давать true)

SWeko
источник
6

Если для ANSI_NULLS установлено значение «ON», и если мы применим =, <> к значению столбца NULL при записи оператора select, то он не вернет никакого результата.

пример

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

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

УСТАНОВИТЬ ANSI_NULLS ON

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)

ВЫКЛЮЧИТЬ 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)
Прават Бехурия
источник
2
+1 за ЕДИНСТВЕННЫЙ ответ, который четко различает WHERE X IS NULLи WHERE X = NULL, и как ANSI_NULLS влияет на результат. Несмотря на излишне рьяные попытки оппонентов, ЭТО должен быть принятым ответом!
Riegardt Steyn 08
1
+1 за объяснение с использованием примеров, которые всегда будут более ясными и краткими, а не длинными предложениями.
peter.aryanto
3

УСТАНОВИТЬ ANSI_NULLS ON

IT возвращает все значения, включая нулевые значения в таблице

ВЫКЛЮЧИТЬ ANSI_NULLS

Заканчивается, когда столбцы содержат нулевые значения

Иосиф Сталин
источник
2
Что еще этот ответ добавляет к уже указанным ответам? С осторожностью добавляйте новые ответы на старые вопросы - они должны содержать расширенное объяснение уже опубликованных решений или предоставлять новое понимание - Из обзора
Takarii
1

Думаю, здесь главное:

Никогда не пользователь:

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

Всегда используйте:

  • @anything IS NULL
  • @anything IS NOT NULL
user369142
источник
0

Если установить ANSI NULLS OFF, сравнение NULL = NULL вернет истинное значение. Например:

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

вернет результат, как показано ниже: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

Пока этот запрос не вернет никаких результатов:

        SET ANSI_NULLS ON 
        select * from sys.tables
        where principal_id = Null
Решение проблем
источник
0

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

Когда для SET ANSI_NULLS установлено значение ON, инструкция SELECT, использующая WHERE column_name = NULL, возвращает нулевые строки, даже если в столбце имя_столбца есть нулевые значения. Оператор SELECT, использующий WHERE column_name <> NULL, возвращает нулевые строки, даже если в column_name есть ненулевые значения.

Например,

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 !
Прасант VJ
источник