I have the following hierarchical structure:
A -> E -> C -> D | | |-> B -> D
Here is the closure table I’ve come up with:
| Ancestor | Descendant | Depth | | A | A | 0 | | B | B | 0 | | C | C | 0 | | D | D | 0 | | E | E | 0 | | A | E | 1 | | A | B | 1 | | A | C | 2 | | E | C | 1 | | A | D | 3 | | E | D | 2 | | C | D | 1 | | A | D | 2 | | B | D | 1 |
I want to remove the link between B and D, and therefore I want to delete the link between A and D (the one of depth 2). The problem is that I don’t want to delete the link between A and D of depth 3 since I didn’t delete the link between C and D.
For the moment, here is the SQL statement to list the links I want to delete:
SELECT link.ancestor, link.descendant, link.depth
FROM closure_table p,
closure_table link,
closure_table c
WHERE p.ancestor = link.ancestor
AND c.descendant = link.descendant
AND p.descendant = B
AND c.ancestor = D;
but this statement give me rows I don’t want to delete:
| Ancestor | Descendant | Depth | | A | D | 2 | | A | D | 3 | <- As said before, I want to keep this one | B | D | 1 |
Advertisement
Answer
I think I’ve found the solution, for those who are interested:
declare @Descendant nchar(10) = 'D'; declare @Ancestor nchar(10) = 'B'; with cte as ( select Ancestor, Depth from closure_table where Descendant = @Descendant and Ancestor = @Ancestor and Depth = 1 union all select r.Ancestor, l.Depth + 1 as Depth from cte as l join closure_table as r on r.Descendant = l.Ancestor where r.Depth = 1 ) delete closure_table from closure_table join cte on cte.Ancestor = closure_table.Ancestor and cte.Depth = closure_table.Depth where closure_table.Descendant = @Descendant;