如何在分层表中的一行(行)中显示所有父 ID

pho*_*nix 0 t-sql common-table-expression hierarchical-data

我有一个分层表,其中为每个孩子定义了一个父 id(除了父 id 为空的顶级孩子)。现在我想为选定的孩子在一行中显示每个父 ID。

我试图使用 CTE,但 CTE 正在向初始集添加额外的记录。相反,我想用父母列表更新初始集(SELECT 语句选择一些孩子)。

表示例(表 1):

ChildID   ParentID
A         P
P         Q
Q         Z
B         P
C         F
F         M
M         Q
D         H
H         Y
Y         NULL
Z         NULL
Run Code Online (Sandbox Code Playgroud)

如果初始语句将从子 ID 列表中选择 C、A、Q,则预期结果如下:

Selected Child    Parent IDs
C                 F, M, Q, Z
A                 P, Q, Z
Q                 Z    
Run Code Online (Sandbox Code Playgroud)

bob*_*per 5

您使用 CTE 执行此操作是正确的,但是您必须将所有行放入一列中(请参阅交叉应用 - xml 路径)。

with cte (selected, child, parent) as 
(  
  select s.id, t.*
  from @t as t
  inner join @selected as s on t.childid = s.id

  union all

  select cte.selected, t.*
  from @t as t
  inner join cte on t.childid = cte.parent
  where cte.parent is not null
)

select distinct
  t.selected as [Selected Child], 
  left(a.parents,len(a.parents) - 1) as Parents
from  cte t
  cross apply (select  cast(parent + ',' as text)
           from cte tt
           where t.selected = tt.selected
           for xml path('')) a(parents);
Run Code Online (Sandbox Code Playgroud)

使用样本数据:

declare @t as table
( 
  childid char(1),
  parentid char(1)
);

declare @selected as table
(
  id char(1)
);


insert into @t (childid,parentid) values ('a','p'),
           ('p','q'),
           ('q','z'),
           ('b','p'),
           ('c','f'),
           ('f','m'),
           ('m','q'),
           ('d','h'),
           ('h','y'),
           ('y',null),
           ('z',null);

insert into @selected (id) values ('c'),('a'),('q');

with cte (selected, child, parent) as 
(  
  select s.id, t.*
  from @t as t
  inner join @selected as s on t.childid = s.id

  union all

  select cte.selected, t.*
  from @t as t
  inner join cte on t.childid = cte.parent
  where cte.parent is not null
)

select distinct
  t.selected as [Selected Child], 
  left(a.parents,len(a.parents) - 1) as Parents
from  cte t
  cross apply (select  cast(parent + ',' as text)
           from cte tt
           where t.selected = tt.selected
           for xml path('')) a(parents);
Run Code Online (Sandbox Code Playgroud)