where子句中的SQL和NULL值

时间:2010-10-14 21:04:25

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

所以我有一个简单的查询返回产品列表

SELECT     Model, CategoryID
FROM         Products
WHERE     (Model = '010-00749-01') 

返回

010-00749-01    00000000-0000-0000-0000-000000000000
010-00749-01    NULL

哪个是正确的,所以我只想要CategoryID不是'00000000-0000-0000-0000-000000000000'的产品,所以我有

SELECT     Model, CategoryID
FROM         Products
WHERE     (Model = '010-00749-01') 
AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 

但是这没有结果。所以我将查询更改为

SELECT     Model, CategoryID
FROM         Products
WHERE     (Model = '010-00749-01') 
AND ((CategoryID <> '00000000-0000-0000-0000-000000000000') OR  (CategoryID  IS NULL))

返回预期结果

010-00749-01    NULL

有人可以向我解释这种行为吗? MS SQL Server 2008

6 个答案:

答案 0 :(得分:9)

查看Books Online的完整参考资料 - 默认情况下,ANSI_NULLS表示您需要使用已完成的方法。否则,您可以在查询开始时将该设置关闭以切换行为。

  

当SET ANSI_NULLS为ON时,为SELECT   使用WHERE column_name的语句   = NULL返回零行,即使column_name中有空值也是如此。一个   使用WHERE的SELECT语句   column_name&lt;&gt; NULL返回零行   即使有非空值   列名。   
...
  当SET ANSI_NULLS时   是ON,所有与null的比较   值评估为UNKNOWN。当SET   ANSI_NULLS为OFF,比较所有   针对空值的数据评估为   如果数据值为NULL,则为TRUE。

这是一个简单的例子,用于演示与NULL比较的行为:

-- This will print TRUE
SET ANSI_NULLS OFF;
IF NULL <> 'A'
    PRINT 'TRUE'
ELSE
    PRINT 'FALSE'

-- This will print FALSE
SET ANSI_NULLS ON;
IF NULL <> 'A'
    PRINT 'TRUE'
ELSE
    PRINT 'FALSE'

答案 1 :(得分:2)

通常,您必须记住NULL通常表示UNKNOWN。这意味着如果你说CategoryID <> '00000000-0000-0000-0000-000000000000',你必须假设查询只会返回它知道符合你标准的值。由于存在NULL(UNKNOWN)结果,因此实际上并不知道该记录是否符合您的条件,因此不会在数据集中返回。

答案 2 :(得分:1)

看看这个:

1=1        --true
1=0        --false
null=null  --false
null=1     --false

1<>1       --false
1<>0       --true
null<>null --false
null<>1    --false    <<<--why you don't get the row with: AND (CategoryID <> '00000000-0000-0000-0000-000000000000') 

答案 3 :(得分:1)

基本上,NULL是缺少任何值。因此,尝试将CategoryId中的NULL与查询中的varchar值进行比较将始终导致错误评估。

您可能想尝试使用COALESCE功能,例如:

SELECT     ModelId, CategoryID 
FROM       Products 
WHERE      (ModelId = '010-00749-01')  
AND        ( COALESCE( CategoryID, '' ) <> '00000000-0000-0000-0000-000000000000' ) 

修改

AdaTheDev所述,COALESCE函数将否定CategoryID列上可能存在的任何索引,这可能会影响查询计划和性能。

答案 4 :(得分:0)

Null得到特殊待遇。您需要显式测试null。见http://msdn.microsoft.com/en-us/library/ms188795.aspx

答案 5 :(得分:0)

您可以尝试使用Coalesce功能为null字段设置默认值:

   SELECT    Model , CategoryID
   FROM      Products
   WHERE     Model = '010-00749-01'
     AND     Coalesce(CategoryID,'') <> '00000000-0000-0000-0000-000000000000'

我认为问题在于你对NULL的理解,这基本上意味着什么都没有。你无法将任何东西与任何东西进行比较,就像你不能将数字除以0.它只是数学/科学的规则。

修改 正如Ada所指出的,这可能导致索引字段不再使用索引。

解决方案:

  • 您可以使用合并功能创建索引:例如create index ... coalesce(field)
  • 您可以添加not null约束以防止NULL出现
  • 我的事实上的标准是始终指定默认值并且永远不允许空值