nickf
nickf

Reputation: 546045

Find leaf nodes in hierarchical tree

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

Answers (6)

Rakib Hossain
Rakib Hossain

Reputation: 1

select *
from `mytree `
where not exists (select *
                  from `mytree ` as `nodes`
                  where `categories`.`id` = `nodes`.`parent`)

Upvotes: 0

fatbuddha
fatbuddha

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

Sunny srivastav
Sunny srivastav

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

Alexander Kojevnikov
Alexander Kojevnikov

Reputation: 17732

SELECT * FROM mytree AS t1
LEFT JOIN mytree AS t2 ON t1.id=t2.parentid
WHERE t2.parentid IS NULL

Upvotes: 5

Daniel Spiewak
Daniel Spiewak

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

TheSoftwareJedi
TheSoftwareJedi

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

Related Questions