The best way to write this code is to qualify all column references. So I would recommend:
CopySELECT b.N,
(CASE WHEN b.P IS NULL
THEN 'Root'
WHEN (SELECT COUNT(*) FROM BST b2 WHERE b2.P = b.N) > 0
THEN 'Inner'
ELSE 'Leaf'
END)
FROM bst b
ORDER BY N;
This makes it clear that inner query is a correlated subquery, which is counting the number of times that a node in BST has the give node but not as a parent.
What are the conditions? Logically, these are:
CopyCASE WHEN <there is no parent>
WHEN <at least one node has this node as a parent>
ELSE <not a parent and no nodes have this as a parent>
END
Note that I strongly discourage the use of COUNT(*) in correlated subquery to determine if there is any match. It is much better -- both from a performance perspective and a clearness perspective -- to use EXISTS:
CopySELECT b.N,
(CASE WHEN b.P IS NULL
THEN 'Root'
WHEN EXISTS (SELECT 1 FROM BST b2 WHERE b2.P = b.N)
THEN 'Inner'
ELSE 'Leaf'
END)
FROM bst b
ORDER BY N;
For getting Root Node P column value is null. For getting inner columns, P column value would be the ones which is not null but they may appear multiple times so a distinct on column values to get those and finally rest all of the nodes then would be Leaf node.
CopySELECT N,
CASE
WHEN P IS NULL
THEN 'Root'
WHEN N IN (SELECT DISTINCT(P) FROM BST WHERE P IS NOT NULL)
THEN 'Inner'
ELSE 'Leaf'
END
FROM BST
ORDER BY N;
Using a case statement is a way to go. However, to determine if a node is 'Inner' one needs to see if it is a parent to another node i.e. is its value N in the set of all P values.
SELECT N, CASE
WHEN P IS NULL THEN 'Root'
WHEN N IN (SELECT P FROM BST) THEN 'Inner'
ELSE 'Leaf' END as node_type FROM BST ORDER BY N
In your fist query you are comparing n with p column within the subquery which should never be true.
In second query you are comparing n column of outer query with p column of subquery which will return more than 0 if there is at least one leaf under the b.n node otherwise it will return 0.