Dans SQL Server, que signifie «SET ANSI_NULLS ON»?

92

La définition dit:

Lorsque SET ANSI_NULLS a la valeur ON, une instruction SELECT qui utilise WHERE nom_colonne = NULL renvoie zéro ligne même s'il existe des valeurs nulles dans nom_colonne. Une instruction SELECT qui utilise WHERE nom_colonne <> NULL renvoie zéro ligne même s'il existe des valeurs non nulles dans nom_colonne.

Cela signifie-t-il qu'aucune valeur nulle ne sera incluse dans cette requête?

SELECT Region
FROM employees
WHERE Region = @region

Ou ANSI_NULLs concerne-t-il uniquement des requêtes comme celle-ci (où WHEREinclut le mot spécifique NULL)?

SELECT Region
FROM employees
WHERE Region = NULL
Rodniko
la source
1
La réponse n'est pas déjà là dans le 4ème paragraphe de la documentation officielle à partir de laquelle vous avez copié le 1er paragraphe, qui est: -> "SET ANSI_NULLS ON affecte une comparaison uniquement si l'un des opérandes de la comparaison est soit une variable qui est NULL ou un littéral NULL. Si les deux côtés de la comparaison sont des colonnes ou des expressions composées, le paramètre n'affecte pas la comparaison. "
user1451111

Réponses:

68

Cela signifie qu'aucune ligne ne sera retournée si @regionest NULL, lorsqu'elle est utilisée dans votre premier exemple, même s'il y a des lignes dans la table où Regionest NULL.

Quand ANSI_NULLSest activé (ce que vous devriez toujours activer de toute façon, puisque l'option de ne pas l'activer va être supprimée à l'avenir), toute opération de comparaison où (au moins) l'un des opérandes est NULLproduit la troisième valeur logique - UNKNOWN( par opposition à TRUEet FALSE).

UNKNOWNles valeurs se propagent à travers tout opérateur booléen combinant si elles ne sont pas déjà décidées (par exemple ANDavec un FALSEopérande ou ORavec un TRUEopérande) ou des négations ( NOT).

La WHEREclause est utilisée pour filtrer le jeu de résultats produit par la FROMclause, de sorte que la valeur globale de la WHEREclause doit être TRUEpour que la ligne ne soit pas filtrée. Ainsi, si un UNKNOWNest produit par une comparaison, cela entraînera le filtrage de la ligne.


La réponse de @ user1227804 comprend cette citation:

Si les deux côtés de la comparaison sont des colonnes ou des expressions composées, le paramètre n'affecte pas la comparaison.

à partir de *SET ANSI_NULLS

Cependant, je ne sais pas sur quel point il essaie de faire valoir, car si deux NULLcolonnes sont comparées (par exemple en a JOIN), la comparaison échoue toujours:

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 requête ci-dessus renvoie 0 ligne, alors 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)

Renvoie une ligne. Donc, même lorsque les deux opérandes sont des colonnes, cela NULLn'est pas égal NULL. Et la documentation de= n'a rien à dire sur les opérandes:

Lorsque vous comparez deux NULLexpressions, le résultat dépend du ANSI_NULLSparamètre:

Si ANSI_NULLSest défini sur ON, le résultat est NULL1 , suivant la convention ANSI selon laquelle une valeur NULL(ou inconnue) n'est pas égale à une autre NULLvaleur inconnue.

Si ANSI_NULLSest défini sur OFF, le résultat de NULLcomparé à NULLest TRUE.

La comparaison NULLavec une non- NULLvaleur donne toujours FALSE2 .

Cependant, 1 et 2 sont incorrects - le résultat des deux comparaisons est UNKNOWN.


* La signification cryptique de ce texte a finalement été découverte des années plus tard. Cela signifie en fait que, pour ces comparaisons, le paramètre n'a aucun effet et agit toujours comme si le paramètre était activé . Cela aurait été plus clair s'il avait déclaré que SET ANSI_NULLS OFFc'était le paramètre qui n'avait aucun effet.

Damien_The_Unbeliever
la source
1
donc si je vous comprends bien: cela affecte aussi le résultat de l'expression "Where Region = @region" et pas seulement quand j'écris spécifiquement "Where Region = null"?
Rodniko
7

Si ce @Regionn'est pas une nullvaleur (disons @Region = 'South'), il ne retournera pas les lignes où le champ Region est nul, quelle que soit la valeur de ANSI_NULLS.

ANSI_NULLS ne fera une différence que lorsque la valeur de @Regionest null, c'est-à-dire lorsque votre première requête devient essentiellement la seconde.

Dans ce cas, ANSI_NULLS ON ne retournera aucune ligne (car null = nullproduira une valeur booléenne inconnue (aka null)) et ANSI_NULLS OFF renverra toutes les lignes où le champ Region est nul (car null = nulldonnera true)

SWeko
la source
6

Si ANSI_NULLS est défini sur "ON" et si nous appliquons =, <> sur la valeur de colonne NULL lors de l'écriture de l'instruction select, il ne renverra aucun résultat.

Exemple

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

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

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

SET ANSI_NULLS OFF

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
la source
2
+1 pour être la SEULE réponse qui distingue clairement entre WHERE X IS NULLet WHERE X = NULLet comment ANSI_NULLS affecte le résultat. Malgré les tentatives trop zélées des électeurs à la baisse, CECI devrait être la réponse acceptée!
Riegardt Steyn
1
+1 pour expliquer à l'aide d'exemples, qui seront toujours plus clairs et plus concis plutôt que de longues phrases.
peter.aryanto le
3

SET ANSI_NULLS ON

IT Renvoie toutes les valeurs, y compris les valeurs nulles dans la table

SET ANSI_NULLS désactivé

il se termine lorsque les colonnes contiennent des valeurs nulles

Joseph Staline
la source
2
Qu'est-ce que cette réponse ajoute aux réponses déjà énoncées? Méfiez-vous de l'ajout de nouvelles réponses aux anciennes questions - Elles devraient contenir des explications détaillées sur les solutions déjà publiées ou fournir de nouvelles informations - De l'avis
Takarii
1

Je suppose que l'essentiel ici est:

Jamais utilisateur:

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

Utilisez toujours:

  • @anything IS NULL
  • @anything IS NOT NULL
user369142
la source
0

Définir ANSI NULLS OFF rendra la comparaison NULL = NULL vraie. PAR EXEMPLE :

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

renvoie un résultat comme indiqué ci-dessous: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

Bien que cette requête ne renvoie aucun résultat:

        SET ANSI_NULLS ON 
        select * from sys.tables
        where principal_id = Null
Un résolveur de problèmes
la source
0

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

Lorsque SET ANSI_NULLS a la valeur ON, une instruction SELECT qui utilise WHERE nom_colonne = NULL renvoie zéro ligne même s'il existe des valeurs nulles dans nom_colonne. Une instruction SELECT qui utilise WHERE nom_colonne <> NULL renvoie zéro ligne même s'il n'y a pas de valeurs nulles dans nom_colonne.

Pour par exemple

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
la source