sql - 在具有多个相同路径的闭包 table 中删除
sql - Deletion in closure table with multiple same paths
我有以下层次结构:
A -> E -> C -> D
|
|
|-> B -> D
这是闭包 table 我想出了:
| 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 |
我想删除 B
和 D
之间的 link,因此我想删除 A
和 [=17] 之间的 link =](深度之一2
)。问题是我不想删除深度 3
的 A
和 D
之间的 link,因为我没有删除 link 之间的 C
和 D
.
目前,这里是 SQL 语句,用于列出我要删除的 link:
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;
但是这条语句给了我不想删除的行:
| Ancestor | Descendant | Depth |
| A | D | 2 |
| A | D | 3 | <- As said before, I want to keep this one
| B | D | 1 |
您可以select具有所有相同祖先-后代对的最小深度的祖先-后代对:
with edges(s, e) as (
-- the pairs to be removed
select 'A', 'D'
union all
select 'B', 'D'
),
n_l as (
select c.* from closure c where c.ancestor != c.descendant
)
select c.* from n_l c where exists (select 1 from edges e where e.s = c.ancestor and e.e = c.descendant)
and c.depth = (select min(c1.depth) from n_l c1 where c1.ancestor = c.ancestor and c1.descendant = c.descendant);
输出:
ancestor
descendant
depth
A
D
2
B
D
1
我想我找到了解决方案,对于那些感兴趣的人:
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;
我有以下层次结构:
A -> E -> C -> D
|
|
|-> B -> D
这是闭包 table 我想出了:
| 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 |
我想删除 B
和 D
之间的 link,因此我想删除 A
和 [=17] 之间的 link =](深度之一2
)。问题是我不想删除深度 3
的 A
和 D
之间的 link,因为我没有删除 link 之间的 C
和 D
.
目前,这里是 SQL 语句,用于列出我要删除的 link:
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;
但是这条语句给了我不想删除的行:
| Ancestor | Descendant | Depth |
| A | D | 2 |
| A | D | 3 | <- As said before, I want to keep this one
| B | D | 1 |
您可以select具有所有相同祖先-后代对的最小深度的祖先-后代对:
with edges(s, e) as (
-- the pairs to be removed
select 'A', 'D'
union all
select 'B', 'D'
),
n_l as (
select c.* from closure c where c.ancestor != c.descendant
)
select c.* from n_l c where exists (select 1 from edges e where e.s = c.ancestor and e.e = c.descendant)
and c.depth = (select min(c1.depth) from n_l c1 where c1.ancestor = c.ancestor and c1.descendant = c.descendant);
输出:
ancestor | descendant | depth |
---|---|---|
A | D | 2 |
B | D | 1 |
我想我找到了解决方案,对于那些感兴趣的人:
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;