假设我有一个这样的数据库模式:
RowId ParentId Name
------ ---------- ------
1 NULL Level1
2 NULL Level2
3 1 Leaf1
4 1 Leaf2
5 2 Leaf1
6 3 LeafX
基本上,树看起来像这样:
Level1
Leaf1
LeafX
Leaf2
Level2
Leaf1
我需要以最有效和最动态的方式提取LeafX的所有祖先LEVEL。
因此它将输出:Leaf1,Leaf2和Leaf1(Level2)
如何在T-SQL中执行此操作?感谢
答案 0 :(得分:3)
这将为您提供所需的结果。
;with C as
(
select T.rowid,
T.parentid,
T.name,
1 as Lvl
from YourTable as T
where T.parentid is null
union all
select T.rowid,
T.parentid,
T.name,
C.Lvl + 1
from YourTable as T
inner join C
on T.parentid = C.rowid
)
select *
from C
where C.Lvl = (
select C.lvl-1
from C
where C.name = 'LeafX'
)
<强>更新强>
这对你来说可能更快。你必须测试你的数据。
declare @Level int;
with C as
(
select T.rowid,
T.parentid
from @t as T
where T.name = 'LeafX'
union all
select T.rowid,
T.parentid
from @t as T
inner join C
on T.rowid = C.parentid
)
select @Level = count(*) - 1
from C;
with C as
(
select T.rowid,
T.parentid,
T.name,
1 as Lvl
from @t as T
where T.parentid is null
union all
select T.rowid,
T.parentid,
T.name,
C.Lvl + 1
from @t as T
inner join C
on T.parentid = C.rowid
where C.Lvl < @Level
)
select *
from C
where C.Lvl = @Level;
答案 1 :(得分:1)
有几种方法可以做到这一点。我最喜欢的是创建特殊的表Trees_Parents,在那里你将存储每个父节点的evere节点。 所以,如果有这样的结构
RowId ParentId Name
------ ---------- ------
1 NULL Level1
2 NULL Level2
3 1 Leaf1
4 1 Leaf2
5 2 Leaf1
6 3 LeafX
你的Trees_Parents表看起来像
RowId ParentId
------ ----------
1 1
2 2
3 3
3 1
4 4
4 1
5 5
5 2
6 6
6 1
6 3
然后当你需要检索所有孩子时,你只需要写
select RowID from Trees_Parents where ParentId = 1
我在这个表中存储行self以避免使用工会,如果你不需要它就可以编写
select RowID from Trees_Parents where ParentId = 1 and ParentId <> RowId
对于所有的父母,你会写
select ParentId from Trees_Parents where RowId = 6 and ParentId <> RowId
您还可以将Table_Name存储在表Trees_Parents中,以便将其用于不同的表
另一种方法是编写递归的WITH子句,但是如果你的树很大并且它没有经常更改,我认为最好将父数据存储在附加表中
答案 2 :(得分:1)
你可以使用递归解决方案。您需要获得所有节点的Depth =节点的深度 - 1
declare @Temp table (RowId int, ParentId int, Name nvarchar(128))
insert into @Temp
select 1, null, 'Level1' union all
select 2, null, 'Level2' union all
select 3, 1, 'Leaf1' union all
select 4, 1, 'Leaf2' union all
select 5, 2, 'Leaf3' union all
select 6, 3, 'LeafX';
with Parents
as
(
select T.RowId, 0 as Depth from @Temp as T where T.ParentId is null
union all
select T.RowId, P.Depth + 1
from Parents as P
inner join @Temp as T on T.ParentId = P.RowId
)
select T.Name
from Parents as P
outer apply (select TT.Depth from Parents as TT where TT.RowId = 6) as CALC
left outer join @Temp as T on T.RowId = P.RowId
where P.Depth = CALC.Depth - 1
答案 3 :(得分:1)
declare @t table(rowid int, parentid int, name varchar(10))
insert @t values(1,NULL,'Level1')
insert @t values(2,NULL,'Level2')
insert @t values(3,1,'Leaf1')
insert @t values(4,1,'Leaf2')
insert @t values(5,2,'Leaf1')
insert @t values(6,3,'LeafX')
;with a as
(
select rowid, parentid, 0 level from @t where name = 'leafx'
union all
select t.rowid, t.parentid, level + 1 from @t t
join a on a.parentid = t.rowid
), b as
(
select rowid, parentid,name, 0 level from @t where parentid is null
union all
select t.rowid, t.parentid,t.name, level + 1
from b join @t t on b.rowid = t.parentid
)
select rowid, parentid, name from b
where level = (select max(level)-1 from a)
rowid parentid name
5 2 Leaf1
3 1 Leaf1
4 1 Leaf2