No SQL Server, o que significa “SET ANSI_NULLS ON”?

92

A definição diz:

Quando SET ANSI_NULLS está ON, uma instrução SELECT que usa WHERE column_name = NULL retorna zero linhas, mesmo se houver valores nulos em column_name. Uma instrução SELECT que usa WHERE nome_da_coluna <> NULL retorna zero linhas, mesmo se houver valores não nulos em nome_da_coluna.

Isso significa que nenhum valor nulo será incluído nesta consulta?

SELECT Region
FROM employees
WHERE Region = @region

Ou diz ANSI_NULLrespeito apenas a consultas como esta (em que WHEREinclui a palavra específica NULL)?

SELECT Region
FROM employees
WHERE Region = NULL
Rodniko
fonte
1
A resposta já não está no 4º parágrafo da documentação oficial da qual você copiou o 1º parágrafo, que é: -> "SET ANSI_NULLS ON afeta uma comparação apenas se um dos operandos da comparação for uma variável NULL ou um NULL literal. Se ambos os lados da comparação forem colunas ou expressões compostas, a configuração não afetará a comparação. "
user1451111

Respostas:

70

Isso significa que nenhuma linha será retornada se @regionfor NULL, quando usado em seu primeiro exemplo, mesmo se houver linhas na tabela onde Regioné NULL.

Quando ANSI_NULLSestá ligado (que você deve sempre definir de qualquer maneira, uma vez que a opção de não tê-lo ativado será removida no futuro), qualquer operação de comparação onde (pelo menos) um dos operandos está NULLproduz o terceiro valor lógico - UNKNOWN( em oposição a TRUEe FALSE).

UNKNOWNos valores se propagam por meio de qualquer combinação de operadores booleanos se ainda não estiverem decididos (por exemplo, ANDcom um FALSEoperando ou ORcom um TRUEoperando) ou negações ( NOT).

A WHEREcláusula é usada para filtrar o conjunto de resultados produzido pela FROMcláusula, de modo que o valor geral da WHEREcláusula deve ser TRUEpara que a linha não seja filtrada. Portanto, se um UNKNOWNfor produzido por qualquer comparação, ele fará com que a linha seja filtrada.


A resposta de @ user1227804 inclui esta citação:

Se ambos os lados da comparação forem colunas ou expressões compostas, a configuração não afetará a comparação.

de *SET ANSI_NULLS

No entanto, não tenho certeza de que ponto ele está tentando fazer, pois se duas NULLcolunas forem comparadas (por exemplo, em a JOIN), a comparação ainda falhará:

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

A consulta acima retorna 0 linhas, enquanto:

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)

Retorna uma linha. Portanto, mesmo quando ambos os operandos são colunas, NULLnão é igual NULL. E a documentação para= não tem nada a dizer sobre os operandos:

Quando você compara duas NULLexpressões, o resultado depende da ANSI_NULLSconfiguração:

Se ANSI_NULLSfor definido como ON, o resultado será NULL1 , seguindo a convenção ANSI de que um valor NULL(ou desconhecido) não é igual a outro NULLvalor desconhecido.

Se ANSI_NULLSfor definido como OFF, o resultado de NULLcomparado com NULLé TRUE.

Comparar NULLcom um NULLvalor não sempre resulta em FALSE2 .

No entanto, 1 e 2 estão incorretos - o resultado de ambas as comparações é UNKNOWN.


* O significado enigmático deste texto foi finalmente descoberto anos depois. O que realmente significa é que, para essas comparações, a configuração não tem efeito e sempre atua como se a configuração estivesse ativada . Teria sido mais claro se tivesse declarado que SET ANSI_NULLS OFFera a configuração que não teve efeito.

Damien_The_Unbeliever
fonte
1
então, se eu entendi direito: ele afeta o resultado da frase "Onde Região = @region" também e não apenas quando escrevo especificamente "Onde Região = null"?
Rodniko
7

Se @Regionnão for um nullvalor (digamos @Region = 'South'), ele não retornará linhas onde o campo Região é nulo, independentemente do valor de ANSI_NULLS.

ANSI_NULLS só fará diferença quando o valor de @Regionénull , ou seja, quando sua primeira consulta se tornar essencialmente a segunda.

Nesse caso, ANSI_NULLS ON não retornará nenhuma linha (porque null = nullproduzirá um valor booleano desconhecido (também conhecido como null)) e ANSI_NULLS OFF retornará quaisquer linhas em que o campo Região seja nulo (porque null = nullproduzirá true)

SWeko
fonte
7

Se ANSI_NULLS for definido como "ON" e se aplicarmos =, <> no valor da coluna NULL ao escrever a instrução select, ele não retornará nenhum resultado.

Exemplo

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

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

DEFINIR ANSI_NULLS LIGADO

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)

DEFINIR ANSI_NULLS DESLIGADO

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
fonte
2
+1 por ser a ÚNICA resposta que distingue claramente entre WHERE X IS NULLe WHERE X = NULL, e como ANSI_NULLS afeta o resultado. Apesar das tentativas excessivamente zelosas dos eleitores inferiores, ESTA deve ser a resposta aceita!
Riegardt Steyn
1
+1 para explicar usando exemplos, que serão sempre mais claros e concisos ao invés de frases longas.
peter.aryanto
3

DEFINIR ANSI_NULLS LIGADO

IT Retorna todos os valores, incluindo valores nulos na tabela

DEFINIR ANSI_NULLS desligado

Termina quando as colunas contêm valores nulos

Joseph Stalin
fonte
2
O que mais essa resposta adiciona às respostas já declaradas? Desconfie de adicionar novas respostas a perguntas antigas - Elas devem conter uma explicação expandida sobre as soluções já postadas ou fornecer uma nova visão - Da avaliação
Takarii
1

Acho que o principal aqui é:

Nunca usuário:

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

Sempre use:

  • @anything IS NULL
  • @anything IS NOT NULL
user369142
fonte
0

Definir ANSI NULLS OFF fará com que a comparação NULL = NULL retorne verdadeira. POR EXEMPLO :

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

retornará algum resultado conforme mostrado abaixo: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

Embora esta consulta não retorne nenhum resultado:

        SET ANSI_NULLS ON 
        select * from sys.tables
        where principal_id = Null
Solucionador de problema
fonte
0

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

Quando SET ANSI_NULLS está ON, uma instrução SELECT que usa WHERE column_name = NULL retorna zero linhas, mesmo se houver valores nulos em column_name. Uma instrução SELECT que usa WHERE nome_da_coluna <> NULL retorna zero linhas, mesmo se houver valores não nulos em nome_da_coluna.

Por exemplo

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
fonte