SQL Server 2008R2: SET ANSI_NULLS OFF 不影响与空值的合并匹配
SQL Server 2008R2: SET ANSI_NULLS OFF does not affect merge matching with null values
我已经阅读了 "SET ANSI_NULLS OFF" 在当前会话中的使用,以便能够将 NULL = NULL 评估为真,例如以下示例显示了 ANSI_NULLS ON 和 ANSI_NULLS OFF 之间的差异:
查询 A:
SET ANSI_NULLS OFF
IF(NULL = NULL)
SELECT 'NULL = NULL'
ELSE
SELECT 'NO MATCH'
结果:'NULL = NULL'
查询 B:
SET ANSI_NULLS ON
IF(NULL = NULL)
SELECT 'NULL = NULL'
ELSE
SELECT 'NO MATCH'
结果:'NO MATCH'
所以这显示了 ON 和 OFF 设置之间的区别。
在标准 select 语句的 where 子句中使用它时,这似乎也有效。
但是,当源字段和目标字段为空时,这在合并中似乎不起作用。
重现一个简单的场景:
创建测试TABLE:
CREATE TABLE [dbo].[TestTable]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[SomeText] [NVARCHAR](100) NULL,
[Counter] [INT] NOT NULL,
CONSTRAINT [PK_TestTable]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
GO
合并查询
MERGE INTO TestTable AS Target
USING (VALUES(NULL)) AS Source(SomeText) ON Target.SomeText = Source.SomeText
WHEN MATCHED THEN
UPDATE SET Target.Counter = Target.Counter + 1
WHEN NOT MATCHED THEN
INSERT (SomeText) VALUES(Source.SomeText);
如果匹配,则计数器加1。如果不匹配,则插入新行。当 运行 查询两次时,结果是两行,这不是我在 ansi_nulls 关闭时所期望的结果。
如果我将值 NULL 更改为 'test',则匹配工作正常,例如
使用(值(NULL))=>使用(值('test'))
使用合并时是否有一些特殊行为可以解释这一点?还是 sql 服务器中的错误?
注意:我不是在寻找使用 ISNULL(...) 解决方案或类似解决方案的变通方法。这样我无法确保有效使用匹配字段的索引。最初的问题是关于与多个匹配字段的合并,其中多个匹配字段可能恰好为空。
仅解决方法!
如果您想处理空值,您可以将 ON
条件从 Target.SomeText = Source.SomeText
更改为 IS NOT DISTINCT FROM
等价物:
MERGE INTO TestTable AS Target
USING (VALUES(NULL)) AS Source(SomeText)
ON EXISTS (SELECT Target.SomeText INTERSECT SELECT Source.SomeText)
WHEN MATCHED THEN
UPDATE SET Target.Counter = ISNULL(Target.Counter,1) + 1
WHEN NOT MATCHED THEN
INSERT (SomeText) VALUES(Source.SomeText);
我同意您应该避免使用 SET ANSI_NULLS OFF
的评论,因为它已被弃用。
SET ANSI_NULLS
仅在非常有限的情况下影响 NULL
比较的语义。具体来说
affects a comparison only if one of the operands of the comparison is
either a variable that is NULL or a literal NULL. If both sides of the
comparison are columns or compound expressions, the setting does not
affect the comparison. (source)
当您将文字 NULL
包装在派生 table 中时,不再满足此条件,因此预计此设置不会如您所愿。
我已经阅读了 "SET ANSI_NULLS OFF" 在当前会话中的使用,以便能够将 NULL = NULL 评估为真,例如以下示例显示了 ANSI_NULLS ON 和 ANSI_NULLS OFF 之间的差异:
查询 A:
SET ANSI_NULLS OFF
IF(NULL = NULL)
SELECT 'NULL = NULL'
ELSE
SELECT 'NO MATCH'
结果:'NULL = NULL'
查询 B:
SET ANSI_NULLS ON
IF(NULL = NULL)
SELECT 'NULL = NULL'
ELSE
SELECT 'NO MATCH'
结果:'NO MATCH'
所以这显示了 ON 和 OFF 设置之间的区别。
在标准 select 语句的 where 子句中使用它时,这似乎也有效。
但是,当源字段和目标字段为空时,这在合并中似乎不起作用。
重现一个简单的场景:
创建测试TABLE:
CREATE TABLE [dbo].[TestTable]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[SomeText] [NVARCHAR](100) NULL,
[Counter] [INT] NOT NULL,
CONSTRAINT [PK_TestTable]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
GO
合并查询
MERGE INTO TestTable AS Target
USING (VALUES(NULL)) AS Source(SomeText) ON Target.SomeText = Source.SomeText
WHEN MATCHED THEN
UPDATE SET Target.Counter = Target.Counter + 1
WHEN NOT MATCHED THEN
INSERT (SomeText) VALUES(Source.SomeText);
如果匹配,则计数器加1。如果不匹配,则插入新行。当 运行 查询两次时,结果是两行,这不是我在 ansi_nulls 关闭时所期望的结果。
如果我将值 NULL 更改为 'test',则匹配工作正常,例如
使用(值(NULL))=>使用(值('test'))
使用合并时是否有一些特殊行为可以解释这一点?还是 sql 服务器中的错误?
注意:我不是在寻找使用 ISNULL(...) 解决方案或类似解决方案的变通方法。这样我无法确保有效使用匹配字段的索引。最初的问题是关于与多个匹配字段的合并,其中多个匹配字段可能恰好为空。
仅解决方法!
如果您想处理空值,您可以将 ON
条件从 Target.SomeText = Source.SomeText
更改为 IS NOT DISTINCT FROM
等价物:
MERGE INTO TestTable AS Target
USING (VALUES(NULL)) AS Source(SomeText)
ON EXISTS (SELECT Target.SomeText INTERSECT SELECT Source.SomeText)
WHEN MATCHED THEN
UPDATE SET Target.Counter = ISNULL(Target.Counter,1) + 1
WHEN NOT MATCHED THEN
INSERT (SomeText) VALUES(Source.SomeText);
我同意您应该避免使用 SET ANSI_NULLS OFF
的评论,因为它已被弃用。
SET ANSI_NULLS
仅在非常有限的情况下影响 NULL
比较的语义。具体来说
affects a comparison only if one of the operands of the comparison is either a variable that is NULL or a literal NULL. If both sides of the comparison are columns or compound expressions, the setting does not affect the comparison. (source)
当您将文字 NULL
包装在派生 table 中时,不再满足此条件,因此预计此设置不会如您所愿。