Rod*_*iko 80 sql t-sql stored-procedures
定义说:
当SET ANSI_NULLS为ON时,即使column_name中存在空值,使用WHERE column_name = NULL的SELECT语句也会返回零行.使用WHERE column_name <> NULL的SELECT语句返回零行,即使column_name中存在非空值也是如此.
这是否意味着此查询中不包含空值?
SELECT Region
FROM employees
WHERE Region = @region
Run Code Online (Sandbox Code Playgroud)
或者ANSI_NULL只关注像这样的查询(其中WHERE包含特定的单词NULL)?
SELECT Region
FROM employees
WHERE Region = NULL
Run Code Online (Sandbox Code Playgroud)
Dam*_*ver 60
这意味着,没有行被返回,如果@region是NULL,即使有在表中的行中的第一个例子中使用时,Region是NULL.
当ANSI_NULLS打开时(无论如何你应该始终设置,因为将来不会删除没有打开的选项),任何比较操作,其中(至少)其中一个操作数NULL产生第三个逻辑值 - UNKNOWN(而不是TRUE和FALSE).
UNKNOWN值传播通过任何结合的布尔运算符,如果他们不已经决定(例如,AND具有FALSE操作数或OR与TRUE操作数)或否定(NOT).
该WHERE子句用于过滤FROM子句生成的结果集,这样子句的整体值WHERE必须是TRUE不过滤掉的行.因此,如果UNKNOWN通过任何比较生成a,则会导致该行被过滤掉.
@ user1227804的答案包含这个引用:
如果比较的两侧都是列或复合表达式,则该设置不会影响比较.
但是,我不确定它要做什么,因为如果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
Run Code Online (Sandbox Code Playgroud)
上面的查询返回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)
Run Code Online (Sandbox Code Playgroud)
返回一行.所以即使两个操作数都是列,NULL也不相等NULL.并且文档对=操作数没有任何说明:
比较两个
NULL表达式时,结果取决于ANSI_NULLS设置:如果
ANSI_NULLS设置为ON,则结果为NULL1,遵循ANSI约定,NULL(或未知)值不等于另一个NULL或未知值.如果
ANSI_NULLS设置为OFF,则NULL比较结果NULL为TRUE.与
NULL非NULL值相比总是导致FALSE2.
但是,1和2都不正确 - 两个比较的结果都是UNKNOWN.
*多年后终于发现了这篇文章的神秘含义.它实际意味着,对于那些比较,设置没有任何效果,它总是表现为设置为ON.如果说它SET ANSI_NULLS OFF是没有影响的设置,那就更清楚了.
小智 27
如果 ANSI_NULLS 设置为“ON”,并且如果我们在编写 select 语句时对 NULL 列值应用 = , <> ,则它将不会返回任何结果。
例子
create table #tempTable (sn int, ename varchar(50))
insert into #tempTable
values (1, 'Manoj'), (2, 'Pankaj'), (3, NULL), (4, 'Lokesh'), (5, 'Gopal')
Run Code Online (Sandbox Code Playgroud)
设置 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)
Run Code Online (Sandbox Code Playgroud)
设置 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)
Run Code Online (Sandbox Code Playgroud)
我想这里最主要的是:
切勿使用:
@anything = NULL@anything <> NULL@anything != null因为 ANSI NULL ON/OFF 可能会改变你的逻辑。
始终使用:
@anything IS NULL@anything IS NOT NULL因为无论 ANSI NULL 是什么,它都会工作
如果@Region不是null值(假设@Region = 'South')它将不返回Region字段为null的行,而不管ANSI_NULLS的值.
ANSI_NULLS只会在@Regionis 的值时产生差异null,即当您的第一个查询基本上成为第二个查询时.
在这种情况下,ANSI_NULLS ON将不返回任何行(因为null = null将产生未知的布尔值(aka null))并且ANSI_NULLS OFF将返回Region字段为null的任何行(因为null = null将产生true)