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
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.
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:
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.
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:
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With