1

我已经阅读了在当前会话中使用“SET ANSI_NULLS OFF”以便能够将 NULL = NULL 评估为 true,例如,以下示例显示了 ANSI_NULLS ON 和 ANSI_NULLS OFF 之间的区别:

问题一:

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'

结果:“不匹配”

因此,这显示了 ON 和 OFF 设​​置之间的差异。

在标准选择语句的 where 子句中使用它时,这似乎也有效。

但是,当源字段和目标字段为空时,这似乎在合并中不起作用。

重现一个简单的场景:

创建测试表:

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 server中的错误?

注意:我不是在寻找使用 ISNULL(...) 解决方案或类似解决方案的解决方法。这样我就无法确保有效使用匹配字段的索引。最初的问题是关于与多个匹配字段的合并,其中多个匹配字段可能碰巧为空。

4

2 回答 2

1

SET ANSI_NULLSNULL仅在非常有限的情况下影响比较的语义。具体来说

仅当比较的操作数之一是 NULL 变量或文字 NULL 时才会影响比较。如果比较的两边都是列或复合表达式,则设置不影响比较。(来源

当您将文字包装NULL在派生表中时,不再满足此条件,因此预计此设置不会如您所愿。

于 2018-12-24T09:21:23.367 回答
0

仅解决方法!

如果要处理空值,可以将ON条件从更改Target.SomeText = Source.SomeTextIS 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);

db<>小提琴演示

我同意您应该避免使用的评论,SET ANSI_NULLS OFF因为它已被弃用。

于 2018-12-21T19:43:33.353 回答