SQL 和 where 子句中的 NULL 值

发布于 2024-09-28 05:03:51 字数 850 浏览 2 评论 0原文

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

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

这返回

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

这是正确的,所以我只想要类别ID不是'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))

Which returns预期结果

010-00749-01    NULL

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

So I have a simple query that returns a listing of products

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

This returns

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

Which is correct, so I wanted only the products whose CategoryID is not '00000000-0000-0000-0000-000000000000' so I have

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

But this returns no result. So I changed the query to

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

Which returns expected result

010-00749-01    NULL

Can someone explain this behavior to me?
MS SQL Server 2008

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

再可℃爱ぅ一点好了 2024-10-05 05:03:51

查看联机丛书上的完整参考资料- 默认情况下 ANSI_NULLS 处于开启状态,这意味着您需要使用您已经完成的方法。否则,您可以在查询开始时关闭该设置以切换行为。

当 SET ANSI_NULLS 为 ON 时,SELECT
使用 WHERE column_name 的语句
= NULL 即使column_name 中存在空值也会返回零行。一个
使用 WHERE 的 SELECT 语句
列名 <> NULL 返回零行
即使其中有非空值
列名。

...
当设置 ANSI_NULLS 时
为 ON 时,所有与空值的比较
值评估为未知。当设置时
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'

Check out the full reference on Books Online - by default ANSI_NULLS is on meaning you'd need to use the approach you have done. Otherwise, you could switch that setting OFF at the start of the query to switch the behaviour round.

When SET ANSI_NULLS is ON, a SELECT
statement that uses WHERE column_name
= NULL returns zero rows even if there are null values in column_name. A
SELECT statement that uses WHERE
column_name <> NULL returns zero rows
even if there are nonnull values in
column_name.

...
When SET ANSI_NULLS
is ON, all comparisons against a null
value evaluate to UNKNOWN. When SET
ANSI_NULLS is OFF, comparisons of all
data against a null value evaluate to
TRUE if the data value is NULL.

Here's a simple example to demonstrate the behaviour with regard to comparisons against 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'
孤独难免 2024-10-05 05:03:51

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

In general, you have to remember that NULL generally means UNKNOWN. That means if you say CategoryID <> '00000000-0000-0000-0000-000000000000' you have to assume that the query will only return values that it KNOWS will meet your criteria. Since there is a NULL (UNKNOWN) result, it does not actually know if that record meets your criteria and therefore will not be returned in the dataset.

桃气十足 2024-10-05 05:03:51

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

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

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

EDIT

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

Basically, a NULL is the absence of any value. So trying to compare the NULL in CategoryId to a varchar value in the query will always result in a false evaluation.

You might want to try using the COALESCE function, something like:

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

EDIT

As noted by AdaTheDev the COALESCE function will negate any indices that may exist on the CategoryID column, which can affect the query plan and performance.

稀香 2024-10-05 05:03:51

看看这个:

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') 

look at this:

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') 
沦落红尘 2024-10-05 05:03:51

Null 得到特殊对待。您需要显式测试 null。请参阅 http://msdn.microsoft.com/en-us/library/ms188795。 ASPX

Null gets special treatment. You need to explicitly test for null. See http://msdn.microsoft.com/en-us/library/ms188795.aspx

七月上 2024-10-05 05:03:51

您可以尝试使用Coalesce函数为具有null的字段设置默认值:

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

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

编辑:
正如 Ada 所指出的,这可能会导致索引字段不再使用索引。

解决方案:

  • 您可以使用 coalesce 函数创建索引:例如 create index ... coalesce(field)
  • 出现
  • 您可以添加一个 not null 约束来防止NULL 我的事实上的标准是始终分配默认值并且绝不允许空值

You may try using the Coalesce function to set a default value for fields that have null:

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

I think the problem lies in your understanding of NULL which basically means "nothing." You can't compare anything to nothing, much like you can't divide a number by 0. It's just rules of math/science.

Edit:
As Ada has pointed out, this could cause an indexed field to no longer use an index.

Solution:

  • You can create an index using the coalesce function: eg create index ... coalesce(field)
  • You can add a not null constraint to prevent NULLs from ever appearing
  • A de facto standard of mine is to always assign default values and never allow nulls
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文