在SQL Server中,“SET ANSI_NULLS ON”是什么意思?
定义说:
当SET ANSI_NULLS为ON时,即使列名中有空值,使用WHERE column_name = NULL的SELECT语句也会返回零行。 即使列名中有非空值,使用WHERE column_name <> NULL的SELECT语句也会返回零行。
这是否意味着这个查询中不包含空值?
SELECT EmployeeID, LastName, FirstName, Region FROM employees WHERE Region=@region
或者ANSI_NULL
只关心像这样的查询( WHERE
包含特定的单词null
)?
SELECT EmployeeID, LastName, FirstName, Region FROM employees WHERE Region=null
这意味着如果在第一个示例中使用@region
为NULL
情况下,即使表中的Region
为NULL
,也不会返回任何行。
当ANSI_NULLS
是打开的时候(无论如何你总是应该设置这个选项,因为没有打开它的选项将来会被删除),那么至less有一个操作数为NULL
比较操作会产生第三个逻辑值- UNKNOWN
(而不是TRUE
和FALSE
)。
UNKNOWN
值尚未确定(例如AND
与FALSE
操作数或OR
与TRUE
操作数)或否定( NOT
),则通过任何组合布尔运算符传播UNKNOWN
值。
WHERE
子句用于过滤由FROM
子句产生的结果集,使得WHERE
子句的总体值必须为TRUE
以防止行被过滤掉。 因此,如果通过比较产生UNKNOWN
,将导致该行被过滤掉。
@ user1227804的答案包括这个引用:
如果比较的两边都是列或复合expression式,则该设置不会影响比较。
来自SET ANSI_NULLS
*
然而,我不确定它试图做什么,因为如果比较两个NULL
列(例如在一个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
expression式时,结果取决于ANSI_NULLS
设置:如果
ANSI_NULLS
设置为ON
,则结果为NULL
1 ,遵循ANSI约定,NULL
(或未知)值不等于另一个NULL
或未知值。如果
ANSI_NULLS
设置为OFF
,则NULL
与NULL
的结果为TRUE
。将
NULL
与非NULL
值进行比较总是会导致FALSE
2 。
但是, 1和2都不正确 – 两个比较的结果都是UNKNOWN
。
*这段文字的神秘含义终于在几年后被发现。 它实际上意味着,对于那些比较,设置没有效果, 它总是作为设置为ON 。 如果它声明SET ANSI_NULLS OFF
是没有任何影响的设置,它会更清晰。
SET QUOTED_IDENTIFIER开启/closures
它指定SQL Server如何处理单引号和双引号中定义的数据。
当它被设置为ON时 ,在双引号 “”中定义的任何字符集被视为T-SQL标识符 (表名称,过程名称,列名… .etc)
当在单引号“'中定义的任何字符集被视为文字时。
SET QUOTED_IDENTIFIER ON CREATE TABLE "SELECT" ("TABLE" int) -- SUCCESS GO SET QUOTED_IDENTIFIER ON SELECT "sometext" AS Value -- FAIL because “sometext” is not a literal
当它被设置为OFF时 ,单引号或双引号中定义的字符集将被视为文字 。
SET QUOTED_IDENTIFIER OFF CREATE TABLE "SELECT"(“TABLE” int) -- FAIL GO SET QUOTED_IDENTIFIER OFF SELECT "sometext" AS Value -- SUCCESS as “sometext” is treated litral --The default behavior is ON in any database.
SET ANSI_NULLS ON / OFF:
ANSI_NULLS选项指定SQL Server如何使用NULL值处理比较操作。
当它被设置为ON时 , 使用=和<>与NULL进行任何比较都将产生错误的值 。 这是ISO定义的标准行为。 所以要用NULL值进行比较,我们需要使用IS NULL和IS NOT NULL。
当它被设置为OFF时,任何使用=和<>的比较都将像往常一样工作,即NULL = NULL返回true,1 = NULL返回false。
SET ANSI_NULLS ON IF NULL = NULL PRINT 'same' ELSE PRINT 'different' --result: different SET ANSI_NULLS ON IF NULL IS NULL PRINT 'same' ELSE PRINT 'different' -- result: same --============================== SET ANSI_NULLS OFF IF NULL = NULL PRINT 'same' ELSE PRINT 'different' --result: same (now NULL = NULL works as 1=1) --The default behavior is ON in any database.
如果@Region
不是null
值(可以说@Region = 'South'
),它不会返回Region字段为空的行,无论ANSI_NULLS的值如何。
ANSI_NULLS只会在@Region
值为null
,即当第一个查询基本上成为第二个查询时。
在这种情况下,ANSI_NULLS ON不会返回任何行(因为null = null
会产生一个未知的布尔值(aka null
)),并且ANSI_NULLS OFF将返回Region字段为空的任何行(因为null = null
将产生true
)
设置ANSI NULLS OFF将使NULL = NULL比较返回true。 EG:
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
https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-nulls-transact-sql
当SET ANSI_NULLS为ON时,即使列名中有空值,使用WHERE column_name = NULL的SELECT语句也会返回零行。 即使列名中有非空值,使用WHERE column_name <> NULL的SELECT语句也会返回零行。
例如
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 !
SET ANSI_NULLS ON
IT返回表中包含空值的所有值
SET ANSI_NULLSclosures
它在列包含空值时结束