当存在NULL值结果时,NOT IN子查询失败

时间:2013-10-31 22:59:53

标签: sql-server null notin

对不起伙计们,我不知道怎么说这个,但我在where子句中有以下内容:

person_id not in (
    SELECT distinct person_id
    FROM protocol_application_log_devl pal
    WHERE pal.set_id = @set_id
)

当子查询没有返回结果时,我的整个select都无法返回任何内容。为解决此问题,我将子查询中的person_id替换为isnull(person_id, '00000000-0000-0000-0000-000000000000')

它似乎有效,但是有更好的方法来解决这个问题吗?

4 个答案:

答案 0 :(得分:6)

最好还是使用NOT EXISTS

WHERE NOT EXISTS(
    SELECT 1 FROM protocol_application_log_devl pal
    WHERE pal.person_id = person_id
     AND  pal.set_id = @set_id
)

Should I use NOT IN, OUTER APPLY, LEFT OUTER JOIN, EXCEPT, or NOT EXISTS?

  

我看到的模式很多,并且希望我没有,不是。什么时候   我看到这种模式,我畏缩。但不是出于性能原因 - 之后   总之,在这种情况下,它创造了一个足够好的计划:

     

主要问题是如果目标,结果可能会令人惊讶   column NULLable (SQL Server将此处理为左反半   join,但不能可靠地告诉你右边的NULL是否相等   至 - 或不等于 - 左侧的参考)。也,   如果列可以为NULL,则优化可以表现不同,即使   它实际上不包含任何NULL值

     

而不是NOT IN,对此查询模式使用相关的NOT EXISTS 。   始终即可。其他方法可以在性能方面与竞争对手相媲美   其他变量是相同的,但所有其他方法都引入   无论是性能问题还是其他挑战。

答案 1 :(得分:2)

虽然我支持Tim的答案是正确的(在这里 ),但这是IN / NOT IN文档中提到的一个有趣的案例:

  

警告:子查询或表达式返回的任何空值,使用IN或NOT IN与test_expression进行比较,返回UNKNOWN。 将空值与IN或NOT IN一起使用会产生意外结果 1

这就是isnull“修复”问题的原因 - 它会屏蔽任何此类NULL值并避免意外行为。考虑到这一点,以下方法也可行(但请注意不使用NOT IN开头的建议):

person_id not in (
  SELECT distinct person_id
  FROM protocol_application_log_devl pal
  WHERE pal.set_id = @set_id
    AND person_id NOT NULL    -- guard here
)

但是,NULL person_id是可疑的并且可能表示其他问题..

1 以下是证明布丁:

select case when 1 not in (2)       then 1 else 0 end as r1,
       case when 1 not in (2, NULL) then 1 else 0 end as r2
-- r1: 1, r2: 0

答案 2 :(得分:0)

我只是使用null函数将isnull值替换为空值,如下例所示。它解决了我的问题

where isnull(UserId,'') not in (select UserID from users where ...)

答案 3 :(得分:0)

这应该有效:

nvl(person_id, '') not in (
    SELECT distinct person_id
    FROM protocol_application_log_devl pal
    WHERE pal.set_id = @set_id
)