En SQL Server, ¿qué significa "SET ANSI_NULLS ON"?

92

La definición dice:

Cuando SET ANSI_NULLS está en ON, una instrucción SELECT que usa WHERE column_name = NULL devuelve cero filas incluso si hay valores nulos en column_name. Una sentencia SELECT que usa WHERE column_name <> NULL devuelve cero filas incluso si hay valores no nulos en column_name.

¿Significa esto que no se incluirán nulos en esta consulta?

SELECT Region
FROM employees
WHERE Region = @region

¿O se ANSI_NULLrefieren solo a consultas como esta (donde WHEREincluye la palabra específica NULL)?

SELECT Region
FROM employees
WHERE Region = NULL
Rodniko
fuente
1
¿La respuesta no está ya en el cuarto párrafo de la documentación oficial de la que copió el primer párrafo, que es: -> "SET ANSI_NULLS ON afecta una comparación solo si uno de los operandos de la comparación es una variable que es NULL? o un NULL literal. Si ambos lados de la comparación son columnas o expresiones compuestas, la configuración no afecta la comparación ".
user1451111

Respuestas:

68

Significa que no se devolverán filas si @regiones NULL, cuando se usa en su primer ejemplo, incluso si hay filas en la tabla donde Regionestá NULL.

Cuando ANSI_NULLSestá activado (que siempre debe activar de todos modos, ya que la opción de no tenerlo activado se eliminará en el futuro), cualquier operación de comparación en la que (al menos) uno de los operandos se NULLproduce el tercer valor lógico - UNKNOWN( en contraposición a TRUEy FALSE).

UNKNOWNlos valores se propagan a través de cualquier combinación de operadores booleanos si aún no están decididos (por ejemplo, ANDcon un FALSEoperando o ORcon un TRUEoperando) o negaciones ( NOT).

La WHEREcláusula se utiliza para filtrar el conjunto de resultados producido por la FROMcláusula, de modo que el valor total de la WHEREcláusula debe ser TRUEpara que la fila no se filtre. Por lo tanto, si UNKNOWNse produce un por cualquier comparación, hará que la fila se filtre.


La respuesta de @ user1227804 incluye esta cita:

Si ambos lados de la comparación son columnas o expresiones compuestas, la configuración no afecta la comparación.

desde *SET ANSI_NULLS

Sin embargo, no estoy seguro de qué punto está tratando de hacer, ya que si NULLse comparan dos columnas (por ejemplo, en a JOIN), la comparación aún falla:

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

La consulta anterior devuelve 0 filas, mientras que:

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)

Devuelve una fila. Entonces, incluso cuando ambos operandos son columnas, NULLno es igual NULL. Y la documentación de= no tiene nada que decir sobre los operandos:

Cuando compara dos NULLexpresiones, el resultado depende de la ANSI_NULLSconfiguración:

Si ANSI_NULLSse establece en ON, el resultado es NULL1 , siguiendo la convención ANSI de que un valor NULL(o desconocido) no es igual a otro NULLvalor desconocido.

Si ANSI_NULLSse establece en OFF, el resultado de NULLcomparado con NULLes TRUE.

La comparación NULLcon un no NULLvalor siempre da como resultado FALSE2 .

Sin embargo, tanto 1 como 2 son incorrectos; el resultado de ambas comparaciones es UNKNOWN.


* El significado críptico de este texto fue finalmente descubierto años después. Lo que realmente significa es que, para esas comparaciones, la configuración no tiene ningún efecto y siempre actúa como si la configuración estuviera ACTIVADA . Hubiera sido más claro si hubiera dicho que ese SET ANSI_NULLS OFFfue el escenario que no tuvo ningún efecto.

Damien_The_Unbeliever
fuente
1
Entonces, si te entiendo bien: también afecta el resultado de la frase "Where Region = @region" y no solo cuando escribo específicamente "Where Region = null"?
Rodniko
7

Si @Regionno es un nullvalor (digamos @Region = 'South'), no devolverá filas donde el campo Región sea nulo, independientemente del valor de ANSI_NULLS.

ANSI_NULLS solo marcará la diferencia cuando el valor de @Regiones null, es decir, cuando su primera consulta se convierta esencialmente en la segunda.

En ese caso, ANSI_NULLS ON no devolverá ninguna fila (porque null = nullproducirá un valor booleano desconocido (también conocido como null)) y ANSI_NULLS OFF devolverá cualquier fila donde el campo Región sea nulo (porque null = nullcederá true)

SWeko
fuente
6

Si ANSI_NULLS se establece en "ON" y si aplicamos =, <> en el valor de columna NULL mientras escribimos la instrucción select, no devolverá ningún resultado.

Ejemplo

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

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

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

APAGAR 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
fuente
2
+1 por ser la ÚNICA respuesta que distingue claramente entre WHERE X IS NULLy WHERE X = NULL, y cómo ANSI_NULLS afecta el resultado. A pesar de los entusiastas intentos de los votantes en contra, ¡ESTA debería ser la respuesta aceptada!
Riegardt Steyn
1
+1 para explicar usando ejemplos, que siempre serán más claros y concisos en lugar de oraciones largas.
peter.aryanto
3

ACTIVAR ANSI_NULLS

IT Devuelve todos los valores incluidos los valores nulos en la tabla

APAGAR ANSI_NULLS

Termina cuando las columnas contienen valores nulos

Joseph Stalin
fuente
2
¿Qué más agrega esta respuesta a las respuestas ya mencionadas? Tenga cuidado de añadir nuevas respuestas a viejas preguntas - Deben contener explicación ampliada sobre soluciones ya publicados, o proporcionar una nueva visión - De la opinión
Takarii
1

Supongo que lo principal aquí es:

Nunca usuario:

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

Siempre usa:

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

Establecer ANSI NULLS OFF hará que la comparación NULL = NULL devuelva verdadera. P.EJ :

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

devolverá algún resultado como se muestra a continuación: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

Si bien esta consulta no devolverá ningún resultado:

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

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

Cuando SET ANSI_NULLS está en ON, una instrucción SELECT que usa WHERE column_name = NULL devuelve cero filas incluso si hay valores nulos en column_name. Una sentencia SELECT que usa WHERE column_name <> NULL devuelve cero filas incluso si hay valores no nulos en column_name.

Por ejemplo

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
fuente