我有一个包含两列并包含两个记录的表。
SQL表结构:
CREATE TABLE #TEMP_TEST
(
ID bigint NOT NULL,
DESCRIPTION varchar(500) NULL
) ON [PRIMARY]
INSERT INTO #TEMP_TEST VALUES(1, 'obsolete')
INSERT INTO #TEMP_TEST VALUES(2, NULL)
SELECT * FROM #TEMP_TEST
#TEMP_TEST
表中的总虚拟记录
ID | DESCRIPTION |
--------+-------------+
1 | obsolete |
2 | NULL |
使用这些条件查询=
,like
,in
工作正常。
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION ='obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION LIKE 'obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION IN ('obsolete')
正常使用这些结果:
ID | DESCRIPTION |
--------+-------------+
1 | obsolete |
问题:
使用这些条件查询!=
,not like
,not in
效果不佳。
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION != 'obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT LIKE 'obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT IN ('obsolete')
结果:
ID | DESCRIPTION |
--------+-------------+
预期结果:
ID | DESCRIPTION |
--------+-------------+
2 | NULL |
我该怎么做才能获得预期的结果?
如果获得预期结果需要进一步的条件,请审核并给出必要的答案或评论。
答案 0 :(得分:5)
这是因为SQL Server中有三个有价值的逻辑。谓词可以评估为:
在比较SQL Server中的数据时,应始终考虑可能的NULL
。考虑这些谓词:
where 1=1 => evaluates to true
where 2=1 => evaluates to false
where 1=null => evaluates to unknown
where null=null => evaluates to unknown
因此,将NULL
与任何值进行比较,即使NULL
评估为UNKNOWN .
Now you should know how
WHERE clause works. It returns rows where predicate evaluates to
仅为TRUE!
在你的情况下谓词:
WHERE LC2.DESCRIPTION != 'obsolete'
将评估为:
obselete != obselete => false
obselete != null => unknown
因此没有谓词评估为TRUE
的行,结果没有任何结果。
至于你应该怎么做的问题,你可以做以下事情:
WHERE ISNULL(LC2.DESCRIPTION, 'not absolete') != 'obsolete'
但是这里你的谓词不是SARG
,如果为LC2.DESCRIPTION
列创建了任何索引,你将无法获得索引。
标准方法是使用OR
:
WHERE LC2.DESCRIPTION != 'obsolete' OR LC2.DESCRIPTION IS NULL
答案 1 :(得分:4)
您可以使用OR
即使ANSI_NULLS
为ON
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION != 'obsolete' OR LC2.DESCRIPTION IS NULL
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT LIKE 'obsolete' OR LC2.DESCRIPTION IS NULL
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT IN ('obsolete') OR LC2.DESCRIPTION IS NULL
答案 2 :(得分:1)
您可以尝试检查ansi_nulls
是否为ON / OFF。当它设置为ON时,则“过时”' <> NULL是一个UNKNOWN,因此你得不到任何结果。
SET ANSI_NULLS OFF
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION !='obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT LIKE 'obsolete'
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT IN ('obsolete')
另外需要注意的是,将ansi_null设置为OFF并不是一种推荐方式,并且不被认为是一种好习惯,因此您可以像这样使用它,即尝试添加NULL条件的检查:
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION != 'obsolete' OR LC2.DESCRIPTION IS NULL
答案 3 :(得分:1)
尝试这样,
SET ANSI_NULLS OFF
SELECT * FROM #TEMP_TEST LC2 WHERE LC2.DESCRIPTION NOT IN ('obsolete')
ANSI_NULLS ON
此选项指定ANSI NULL比较的设置。启用此选项后,任何将值与null进行比较的查询都将返回0.关闭时,将值与null进行比较的任何查询都将返回空值。