Reputation: 546045
I have a table in my database which stores a tree structure. Here are the relevant fields:
mytree (id, parentid, otherfields...)
I want to find all the leaf nodes (that is, any record whose id
is not another record's parentid
)
I've tried this:
SELECT * FROM mytree WHERE `id` NOT IN (SELECT DISTINCT `parentid` FROM `mytree`)
But that returned an empty set. Strangely, removing the "NOT" returns the set of all the non-leaf nodes.
Can anyone see where I'm going wrong?
Update: Thanks for the answers folks, they all have been correct and worked for me. I've accepted Daniel's since it also explains why my query didn't work (the NULL thing).
Upvotes: 19
Views: 19898
Reputation: 1
select *
from `mytree `
where not exists (select *
from `mytree ` as `nodes`
where `categories`.`id` = `nodes`.`parent`)
Upvotes: 0
Reputation: 1027
Select * from mytree where id not in (Select distinct parentid from mytree where parentid is not null)
http://archives.postgresql.org/pgsql-sql/2005-10/msg00228.php
Upvotes: 1
Reputation: 1
my table structure is
memberid MemberID joiningposition packagetype
RPM00000 NULL Root free
RPM71572 RPM00000 Left Royal
RPM323768 RPM00000 Right Royal
RPM715790 RPM71572 Left free
RPM323769 RPM71572 Right free
RPM715987 RPM323768 Left free
RPM323985 RPM323768 Right free
RPM733333 RPM323985 Right free
RPM324444 RPM715987 *emphasized text*Right Royal
--
ALTER procedure [dbo].[sunnypro]
as
DECLARE @pId varchar(40) = 'RPM00000';
Declare @Id int
set @Id=(select id from registration where childid=@pId)
begin
-- Recursive CTE
WITH R AS
(
SELECT
BU.DateofJoing,
BU.childid,
BU.joiningposition,
BU.packagetype
FROM registration AS BU
WHERE
BU.MemberID = @pId and
BU.joiningposition IN ('Left', 'Right')
or BU.packagetype in('Royal','Platinum','Majestic')
and BU.Id>@id
UNION All
-- Recursive part
SELECT
BU.DateofJoing,
BU.childid,
R.joiningposition,
BU.packagetype
FROM R
JOIN registration AS BU
ON BU.MemberID = R.childid
WHERE
BU.joiningposition IN ('Left', 'Right') and
BU.packagetype in('Royal','Platinum','Majestic')
and BU.Id>@id
)
INSERT INTO Wallatpayout
(childid
,packagetype
,joiningposition
,DateofJoing
,Total)
-- Final groups of nodes found
SELECT top 3
R.childid,
R.packagetype,
R.joiningposition,
R.DateofJoing,
Total = COUNT_BIG(*)
FROM R where R.packagetype in('Royal','Platinum','Majestic')
GROUP BY R.childid,
R.joiningposition,
R.DateofJoing,
R.packagetype
OPTION (MAXRECURSION 0);
end
Upvotes: -2
Reputation: 17732
SELECT * FROM mytree AS t1
LEFT JOIN mytree AS t2 ON t1.id=t2.parentid
WHERE t2.parentid IS NULL
Upvotes: 5
Reputation: 55123
Your query didn't work because the sub-query includes NULL
. The following slight modification works for me:
SELECT * FROM `mytree` WHERE `id` NOT IN (
SELECT DISTINCT `parentid` FROM `mytree` WHERE `parentid` IS NOT NULL)
Upvotes: 25
Reputation: 35196
No clue why your query didn't work. Here's the identical thing in left outer join syntax - try it this way?
select a.*
from mytree a left outer join
mytree b on a.id = b.parentid
where b.parentid is null
Upvotes: 8