1

假设我有一个这样的数据库模式:

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 的所有祖先级别。

所以会输出: Leaf1, Leaf2, and Leaf1 (of Level2)

如何在 T-SQL 中执行此操作?谢谢

4

4 回答 4

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;
于 2012-10-16T08:52:50.247 回答
1

有几种方法可以做到这一点。我最喜欢的是创建特殊的表 Trees_Parents,您将在其中存储每个父节点的所有节点。所以如果有这样的结构

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 子句,但是如果您的树很大并且它不经常更改,我认为最好将父数据存储在附加表中

于 2012-10-16T07:41:45.793 回答
1

那么你可以使用递归解决方案。您需要获取所有节点的深度 = 您节点的深度 - 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
于 2012-10-16T08:06:01.253 回答
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
于 2012-10-16T08:19:36.417 回答