4

对不起,伙计们,我不知道如何表达这个,但我在 where 子句中有以下内容:

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

当子查询不返回任何结果时,我的整个选择都无法返回任何内容。为了解决这个问题,我person_id在子查询中替换为isnull(person_id, '00000000-0000-0000-0000-000000000000').

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

4

4 回答 4

8

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
)

我应该使用 NOT IN、OUTER APPLY、LEFT OUTER JOIN、EXCEPT 还是 NOT EXISTS?

我经常看到的一种模式,但希望我没有看到,它不在。当我看到这种模式时,我会畏缩。但不是出于性能原因——毕竟,在这种情况下,它创建了一个足够体面的计划:

主要问题是,如果目标列是NULLable ,结果可能会令人惊讶(SQL Server 将此作为左反半连接处理,但无法可靠地告诉您右侧的 NULL 是否等于 - 或不等于– 左侧的参考)。此外,如果该列可以为 NULL,则优化的行为可能会有所不同,即使它实际上不包含任何 NULL 值

对此查询模式 使用相关的 NOT EXISTS,而不是 NOT IN 。总是。当所有其他变量都相同时,其他方法可能会在性能方面与它竞争,但所有其他方法都会引入性能问题或其他挑战。

于 2013-10-31T23:05:12.810 回答
2

虽然我支持 Tim 的回答在实践中是正确的(NOT IN 在这里不合适),但这是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
于 2013-10-31T23:13:39.533 回答
1

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

where isnull(UserId,'') not in (select UserID from users where ...)
于 2019-12-07T09:34:47.697 回答
0

这应该有效:

nvl(person_id, '') not in (
    SELECT distinct person_id
    FROM protocol_application_log_devl pal
    WHERE pal.set_id = @set_id
)
于 2020-08-06T15:17:25.473 回答