如何比较可能都为null的值是T-SQL
我想确保我没有插入重复行到我的表(例如只有主键不同)。 我所有的领域都允许NULLS,因为我已经决定为“所有的价值”。 由于空值,我的存储过程中的以下语句无法工作:
IF EXISTS(SELECT * FROM MY_TABLE WHERE MY_FIELD1 = @IN_MY_FIELD1 AND MY_FIELD2 = @IN_MY_FIELD2 AND MY_FIELD3 = @IN_MY_FIELD3 AND MY_FIELD4 = @IN_MY_FIELD4 AND MY_FIELD5 = @IN_MY_FIELD5 AND MY_FIELD6 = @IN_MY_FIELD6) BEGIN goto on_duplicate END
因为NULL = NULL是不正确的。
我怎样才能检查重复没有每个列IF IF NULL语句?
使用INTERSECT
运算符。
如果您在所有字段上都有复合索引,则它是NULL
敏感且高效的:
IF EXISTS ( SELECT MY_FIELD1, MY_FIELD2, MY_FIELD3, MY_FIELD4, MY_FIELD5, MY_FIELD6 FROM MY_TABLE INTERSECT SELECT @IN_MY_FIELD1, @IN_MY_FIELD2, @IN_MY_FIELD3, @IN_MY_FIELD4, @IN_MY_FIELD5, @IN_MY_FIELD6 ) BEGIN goto on_duplicate END
请注意,如果你在你的领域创build一个UNIQUE
索引,你的生活会更简单。
沿着@埃里克的答案 ,但没有使用'NULL'
符号相同的线。
(Field1 = Field2) OR (ISNULL(Field1, Field2) IS NULL)
只有当这两个值都是non-NULL
,并且彼此相等,或者这两个值都是NULL
,这才是真的
使用ISNULL
:
ISNULL(MY_FIELD1, 'NULL') = ISNULL(@IN_MY_FIELD1, 'NULL')
如果更有意义,可以将'NULL'
更改为'All Values'
。
需要注意的是,有两个参数, ISNULL
与COALESCE
工作方式相同,如果您有几个testing值(即COALESCE(@IN_MY_FIELD1, @OtherVal, 'NULL')
),您可以使用它。 在第一个非空之后, COALESCE
也会返回,这意味着如果您期待MY_FIELD1为空白,则它会(稍微)更快。 但是,我发现ISNULL
更具可读性,所以这就是我在这里使用它的原因。
在进行MERGE时,我需要进行类似的比较:
WHEN MATCHED AND (Target.Field1 <> Source.Field1 OR ...)
额外的检查是为了避免更新所有列已经相同的行。 为了我的目的,我希望NULL <> anyValue
为True,而NULL <> NULL
为False。
解决scheme演变如下:
第一次尝试:
WHEN MATCHED AND ( ( -- Neither is null, values are not equal Target.Field1 IS NOT NULL AND Source.Field1 IS NOT NULL AND Target.Field1 <> Source.Field1 ) OR ( -- Target is null but source is not Target.Field1 IS NULL AND Source.Field1 IS NOT NULL ) OR ( -- Source is null but target is not Target.Field1 IS NOT NULL AND Source.Field1 IS NULL ) -- OR ... Repeat for other columns )
第二次尝试:
WHEN MATCHED AND ( -- Neither is null, values are not equal NOT (Target.Field1 IS NULL OR Source.Field1 IS NULL) AND Target.Field1 <> Source.Field1 -- Source xor target is null OR (Target.Field1 IS NULL OR Source.Field1 IS NULL) AND NOT (Target.Field1 IS NULL AND Source.Field1 IS NULL) -- OR ... Repeat for other columns )
第三次尝试(由THEn的答案启发):
WHEN MATCHED AND ( ISNULL( NULLIF(Target.Field1, Source.Field1), NULLIF(Source.Field1, Target.Field1) ) IS NOT NULL -- OR ... Repeat for other columns )
相同的ISNULL / NULLIF逻辑可用于testing相等和不等式:
- 平等:
ISNULL(NULLIF(A, B), NULLIF(B, A)) IS NULL
- Inequaltiy:
ISNULL(NULLIF(A, B), NULLIF(B, A)) IS NOT NULL
这是一个SQL小提琴展示它如何工作http://sqlfiddle.com/#!3/471d60/1
IF EXISTS(SELECT * FROM MY_TABLE WHERE (MY_FIELD1 = @IN_MY_FIELD1 or (MY_FIELD1 IS NULL and @IN_MY_FIELD1 is NULL)) AND (MY_FIELD2 = @IN_MY_FIELD2 or (MY_FIELD2 IS NULL and @IN_MY_FIELD2 is NULL)) AND (MY_FIELD3 = @IN_MY_FIELD3 or (MY_FIELD3 IS NULL and @IN_MY_FIELD3 is NULL)) AND (MY_FIELD4 = @IN_MY_FIELD4 or (MY_FIELD4 IS NULL and @IN_MY_FIELD4 is NULL)) AND (MY_FIELD5 = @IN_MY_FIELD5 or (MY_FIELD5 IS NULL and @IN_MY_FIELD5 is NULL)) AND (MY_FIELD6 = @IN_MY_FIELD6 or (MY_FIELD6 IS NULL and @IN_MY_FIELD6 is NULL))) BEGIN goto on_duplicate END
Wordy与IFNULL / COALESCE解决scheme相比。 但是,不用考虑什么值不会出现在可以用作NULL的数据中。
你可以合并每一个值,但是这有点诱人:
IF EXISTS(SELECT * FROM MY_TABLE WHERE coalesce(MY_FIELD1,'MF1') = coalesce(@IN_MY_FIELD1,'MF1') AND ... BEGIN goto on_duplicate END
您还需要确保coalesced
值在所讨论的列上不是有效的值。 例如,如果MY_FIELD1的值可能是“MF1”,那么这将导致很多虚假命中。
你在你的字段上创build一个主键,让引擎执行唯一性。 不pipe怎样,EXISTS的逻辑是不正确的,因为在比赛条件下是有缺陷的。
如果你想对不相等的值进行比较呢? 只是在前面提到的比较之前使用“NOT”不起作用。 我能想到的最好的是:
(Field1 <> Field2) OR (NULLIF(Field1, Field2) IS NOT NULL) OR (NULLIF(Field2, Field1) IS NOT NULL)
NULLIF(TARGET.relation_id,SOURCE.app_relation_id)IS NULL简单的解决scheme
你将不得不使用IS NULL或ISNULL。 真的没有一个在附近。
您可以使用SET ANSI_NULLS
来指定Equals(=)和Not Equal To(<>)比较运算符与空值一起使用时的行为。