代码之家  ›  专栏  ›  技术社区  ›  Saket Kumar

在这个SQL查询中使用“Not In”有什么错?

  •  3
  • Saket Kumar  · 技术社区  · 8 年前

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

    enter image description here

    这里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
    

    然而,作为中“Leaf”的最后一个条件,这并没有给我期望的结果 Case 语句不满足叶节点。在这种情况下,我得到以下输出:

    enter image description here

    我现在有一个变通方法,如下查询,它将为我提供预期的输出:

    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
    

    预期输出:

    enter image description here

    但我不知道第一个有什么问题。谁能给我解释一下吗?

    5 回复  |  直到 8 年前
        1
  •  1
  •   Caius Jard    8 年前

    问题是因为其中一个P值为null。删除此项,方法是说 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
    

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

    这有点违反直觉,但没有任何东西可以等于或不等于null,甚至不等于null。当一侧为null时使用=会导致null、not true和not false

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

    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
    

        2
  •  1
  •   Mureinik    8 年前

    in 是一系列 = 检查。 null = 在里面 ),它会导致 无效的 ,这不是“真的”。

    你可以想到 无效的 作为“未知”值。一、 e.-从表中选择的值列表中是否有未知值?我们不知道。

    因此,您必须处理 无效的 s,正如您在第二个查询中所做的那样。

        3
  •  1
  •   gotqn user3521065    8 年前

    试试这个:

    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];
    

    enter image description here

    这个想法是使用两个 LEFT JOIN s以查看当前节点是否为子节点,以及当前节点是否为父节点。

        4
  •  1
  •   Suyanhanx    8 年前

    因为P有一个空值。

    使用IS或IS代替。

        5
  •  0
  •   sanjay singh    8 年前

    写notExists而不是not in,这样它就不会考虑null

    案例

    当P为null时,则为“Root”

    当N在(从BST中选择不同的P)时,则为“内部”

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

    结束为类型 从BST作为t1