【问题标题】:What is wrong with using 'Not In' in this SQL query?在这个 SQL 查询中使用“Not In”有什么问题?
【发布时间】:2018-04-27 00:26:06
【问题描述】:

我有一个名为 BST 的表,如下所示:

这里N是二叉树节点的值,P是它的父节点。我必须编写一个查询来确定一个节点是根节点、叶节点还是内部节点。我为此写了下面的 SQL 查询:

select N, 
case
when P is null then 'Root'
when N in (select distinct P from BST) then 'Inner'
when N not in (select distinct P from BST) then 'Leaf'
end as type
from BST

但是,这并没有给我想要的结果,因为 Case 语句中“叶子”的最后一个条件不满足叶子节点。在这种情况下,我得到的输出低于:

我现在有一个解决方法,如下查询,它给了我预期的输出:

select N, 
case
when P is null then 'Root'
when N in (select distinct P from BST) then 'Inner'
else 'Leaf'
end as type
from BST

预期输出:

但我不知道第一个有什么问题。有人可以解释一下吗?

【问题讨论】:

    标签: sql sql-server tsql select null


    【解决方案1】:

    in 是一系列= 检查的简写。 null,不是一个价值——它是缺乏价值。每当将它应用于期望值的运算符(如=in)时,它都会导致null,这不是“真”。

    您可以将null 视为“未知”值。 IE。 - 从表中选择的值列表中是否存在未知值?我们不知道。

    因此,您必须明确处理 nulls,就像您在第二个查询中所做的那样。

    【讨论】:

      【解决方案2】:

      试试这个:

      DECLARE @DataSource TABLE
      (
          [N] TINYINT
         ,[P] TINYINT
      );
      
      INSERT INTO @DataSource ([N], [P])
      VALUES (1, 2)
            ,(3, 2)
            ,(5, 6)
            ,(7, 6)
            ,(2, 4)
            ,(6, 4)
            ,(4, 15)
            ,(8, 9)
            ,(10, 9)
            ,(12, 13)
            ,(14, 13)
            ,(9, 11)
            ,(13, 11)
            ,(11, 15)
            ,(15, NULL);
      
      SELECT DISTINCT 
             DS1.[N]
            ,CASE WHEN DS2.[N] IS NULL THEN 'IsLeaf' ELSE CASE WHEN DS3.[N] IS NOT NULL THEN 'Inner' ELSE ' Root' END END AS [Type]
      FROM @DataSource DS1
      LEFT JOIN @DataSource DS2
          ON DS1.[N] = DS2.[P]
      LEFT JOIN @DataSource DS3
          ON DS1.[P] = DS3.[N]
      ORDER BY [Type];
      

      想法是使用两个LEFT JOINs 来查看当前节点是否为子节点,当前节点是否为父节点。

      【讨论】:

        【解决方案3】:

        问题是因为您的 P 值之一为空。至少在 Not In 您的一个子查询中说 select distinct p from t where p is not null 来删除它

        http://sqlfiddle.com/#!6/77fb8/3

        因此:

        select N, 
        case
        when P is null then 'Root'
        when N in (select distinct P from BST) then 'Inner'
        when N not in (select distinct P from BST where p is not null) then 'Leaf'
        end as type
        from BST
        

        空 P 值包含在所选的不同值列表中,not in 无法确定 N 的给定值是否等于/不等于来自 P 根节点的空值。

        这有点违反直觉,但没有什么等于或不等于空值,甚至不等于空值。使用 = 一侧为 null 的结果为 null,不为真也不为假

        IN 可用于检查一个值是否在列表中,但如果不是,则不检查,如果列表包含空值

        1 IN (1,2,null) --true
        3 IN (1,2,null) --null, not false, null which isn't true
        3 NOT IN (1,2,null) --null, not false, null which isn't true
        

        ELSE 表单是前往此处的方式。或者将不同的查询作为子查询放入 FROM 块中并对其进行左连接

        【讨论】:

          【解决方案4】:

          因为 P 有一个空值。

          您不能将 NULL 与常规(算术)比较运算符进行比较。任何与 NULL 的算术比较都会返回 NULL,即使 NULL = NULL 或 NULL NULL 也会产生 NULL。

          改用 IS 或 IS NOT。

          【讨论】:

            【解决方案5】:

            写 where notExists 而不是 not in 这样它就不会考虑空值

            选择 N,

            案例

            当 P 为 null 时,则为 'Root'

            当 N in (select distinct P from BST) then 'Inner'

            当 N 不存在时(从 BST 中选择 * 作为 t2,其中 t2.N=t1.N) 然后是'叶子'

            作为类型结束 从 BST 作为 t1

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-15
              • 2010-10-21
              • 1970-01-01
              • 1970-01-01
              • 2015-08-08
              • 1970-01-01
              相关资源
              最近更新 更多