为什么Sql条件(不在,不在,等于!=)不能处理表的varchar值

时间:2015-10-22 10:17:55

标签: sql sql-server sql-server-2008

我有一个包含两列并包含两个记录的表。

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        |

使用这些条件查询=likein工作正常。

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 likenot 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        |

我该怎么做才能获得预期的结果?

如果获得预期结果需要进一步的条件,请审核并给出必要的答案或评论。

4 个答案:

答案 0 :(得分:5)

这是因为SQL Server中有三个有价值的逻辑。谓词可以评估为:

  • true
  • 未知

在比较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_NULLSON

也可以使用
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进行比较的任何查询都将返回空值。