Quel est le problème avec l'utilisation de 'Not In' dans cette requête SQL?

J'ai une table appelée BST comme indiqué ci-dessous:

entrez la description de l'image ici

Ici N est la valeur du noeud de l'tree binary et P est son noeud parent. Je dois écrire une requête qui déterminera si un noeud est un noeud racine, un noeud de feuille ou un noeud intérieur. J'ai écrit ci-dessous une requête SQL pour cela:

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 

Cependant, cela ne me donne pas le résultat souhaité car la dernière condition pour 'Feuille' dans l'instruction Case ne satisfait pas pour le noeud feuille. Je reçois en dessous de la sortie dans ce cas:

entrez la description de l'image ici

J'ai une solution de contournement pour le moment comme ci-dessous la requête qui me donne la sortie attendue:

 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 

Production attendue:

entrez la description de l'image ici

Mais je ne peux pas comprendre ce qui ne va pas avec le premier. Quelqu'un pourrait-il m'expliquer cela?

Le problème est que l'une de vos valeurs P est nulle. Supprimez ceci en disant select distinct p from t where p is not null dans au less le Not In d'une de vos sous-requêtes

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

Par conséquent:

 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 

la valeur P nulle est incluse dans la list des valeurs distinctes sélectionnées, et not in peut pas déterminer si une valeur donnée de N est égale / non égale à la valeur nulle provenant du nœud racine de P.

C'est un peu contre-intuitif mais rien n'est jamais égal ou pas égal à un null, pas même nul. using = avec un côté étant nul, donne null, pas vrai et pas faux

IN peut être utilisé pour vérifier si une valeur EST dans la list, mais pas si elle ne l'est pas, si la list contient une valeur nulle

 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 

Le formulaire ELSE est le path à suivre ici. Ou placez la requête disctinct dans une sous-requête dans le bloc FROM et faites-y une jointure à gauche

in est un raccourci pour une série de = vérifications. null , n'est pas une valeur – c'est le manque de cela. Chaque fois que l'appliquer à un opérateur attend une valeur (comme = , ou in ), il en résulte une valeur null , qui n'est pas "vrai".

Vous pouvez considérer null comme une valeur "inconnue". Ie – est une valeur inconnue dans une list de valeurs sélectionnées à partir d'une table? Nous ne pouvons pas savoir.

Ainsi, vous devez gérer explicitement null , comme vous l'avez fait dans votre deuxième requête.

Essaye ça:

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

entrez la description de l'image ici

L'idée est d'utiliser deux LEFT JOIN afin de voir si le nœud actuel est enfant et si le courant n'est pas parent.

Parce que P a une valeur nulle.

Vous ne pouvez pas comparer NULL avec les opérateurs de comparaison réguliers (arithmétiques). Toute comparaison arithmétique à NULL returnnera NULL, même NULL = NULL ou NULL <> NULL donnera NULL.

Utilisez IS ou IS NOT à la place.

Écrivez où notExists au lieu de ne pas entrer afin qu'il ne considère pas les nulls

select N,

Cas

quand P est nul alors 'Root'

quand N dans (select distinct P de BST) puis 'Inner'

quand N n'existe pas (sélectionner * à partir de BST comme t2 où t2.N = t1.N) puis 'Feuille'

fin comme type de BST comme t1