Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Tree find anscestors at a specific level

Say I have the following tree:

CREATE TABLE Tree(Id int, ParentId int, Name varchar(20), Level int)

INSERT INTO Tree(Id, ParentId, Name, Level)
SELECT 1, NULL, 'Bob', 0 UNION ALL 
SELECT 2, 1, 'John', 1 UNION ALL
SELECT 3, 1, 'Bill', 1 UNION ALL
SELECT 4, 3, 'Peter', 2 UNION ALL
SELECT 5, 4, 'Sarah', 3

I need a script to find the ancestor of a given node at a specific level:

For example the ancestor of Sarah at level 2 is Peter, and the ancestor of Peter at level 0 is Bob.

Is there an easy way to do this using a hierarchical CTE? sqlfiddle

like image 440
woggles Avatar asked Sep 25 '12 11:09

woggles


People also ask

What is the level ancestor problem?

The level ancestor problem is the problem of preprocessing a given rooted tree T into a data structure that can determine the ancestor of a given node at a given depth from the root of the tree. Here depth of any node in a tree is the number of edges on the shortest path from the root of the tree to the node.

What is a typical SQL tree structure?

As you can see, it’s a typical SQL tree structure. There are menu nodes which are attached to parent nodes. The only node without a parent is the root node. This is how we store such a SQL tree structure in the database:

How to compute 1st level ancestor of node with value 8?

In the given figure we need to compute 1st level ancestor of the node with value 8. First, we make ancestor matrix which stores 2 ith ancestor of nodes. Now, 20 ancestor of node 8 is 10 and similarly 20 ancestor of node 10 is 9 and for node 9 it is 1 and for node 1 it is 5.

What are the ancestors of a category tree?

And the parents, grandparents, etc., of a node are also known as ancestors. To model this category tree, we can create a table named category with three columns: id, title, and parent_id as follows:


2 Answers

You can do this:

;WITH TreeCTE
AS
(
    SELECT Id, ParentId, Name, Level
    FROM Tree
    WHERE Id = 5
    UNION ALL 
    SELECT t.Id, t.ParentId, t.Name, t.Level
    FROM TreeCTE AS c
    INNER JOIN Tree t ON c.ParentId = t.Id  
)
SELECT * FROM TreeCTE;

This will give you the parent-child chain beginning from Sarah with the id = 5 ending with the top most parent with the parentid = NULL.

Here is the updated sql fiddle

like image 166
Mahmoud Gamal Avatar answered Sep 22 '22 01:09

Mahmoud Gamal


declare @fromid int, @level int
select @fromid = 5, @level = 2 -- for sarah's ancestor at level 2
select @fromid = 4, @level = 0 -- for peter's ancestor at level 0

;with cte as (    
    select * from tree where id = @fromId
    union all
    select t.Id, t.ParentId, t.Name, t.Level from cte
        inner join tree t on t.id = cte.ParentId
) 
    select * from cte
    where Level=@level
like image 36
podiluska Avatar answered Sep 23 '22 01:09

podiluska