具有父子关系的递归查询

Recursive query with parent-child relation

我正在尝试在 SQL 服务器中进行递归查询,以分层显示数据。这是 table

的结构
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [varchar(100)] NOT NULL,
    [Parent_Id] [int] NULL,

每个产品都有父项。 Parent_Id 列包含父级的 ID。 parent_id 对于根产品为空。

我想创建一个 sql 查询来分层显示产品。下图是如何组织产品的示例。

产品可以有子产品。

对于上图,查询结果应该是这样的:

id name      parent_id
1  P1        NULL
2  P2        NULL
3  P2-1      2
4  P2-2      2
5  P2-3      2
6  P2-3-1    5
7  P2-3-2    5
8  P3        NULL
9  P3-1      8

这是我为实现它而写的请求:

with tree as (select * from products
               union all
               select * from tree where parent_id = tree.id
             )
select * from tree;

但我得到的结果类似于以下内容:

1  P1        NULL
2  P2        NULL
8  P3        NULL
3  P2-1      2
4  P2-2      2
5  P2-3      2
9  P3-1      8
6  P2-3-1    5
7  P2-3-2    5

我想要的是对每个兄弟产品进行分组,以便每个产品都显示在其直接父项下。

构造递归查询中的路径。以下将其作为具有固定长度 ID 的字符串执行此操作:

with tree as (
      select p.id, p.name, p.parentid,
             format(p.parentid, '0000') as path
      from products p
      where p.parentid is null
      union all
      select p.id, p.name, p.parentid,
             concat(cte.path, '->', format(p.id, '0000')
      from tree join
           products p
      where p.parent_id = t.id
     )
select *
from tree;

如果我的理解是正确的,并且您得到了您想要的结果但未排序,您应该能够按名称对结果进行排序。

with tree as (select * from products
               union all
               select * from tree where parent_id = tree.id
             )
select * from tree order by name asc;

只是使用数据类型 hierarchyid

的另一种选择

还有一些与 hierarchyid

相关的附加特性和功能

例子

-- Optional See 1st WHERE
Declare @Top int = null  --<<  Sets top of Hier Try 2

;with cteP as (
      Select ID
            ,parent_id 
            ,Name 
            ,HierID = convert(hierarchyid,concat('/',ID,'/'))
      From   YourTable 
      Where  IsNull(@Top,-1) = case when @Top is null then isnull(parent_id ,-1) else ID end
      --Where parent_id is null  -- Use this where if you always want the full hierarchy
      Union  All
      Select ID  = r.ID
            ,parent_id  = r.parent_id 
            ,Name   = r.Name
            ,HierID = convert(hierarchyid,concat(p.HierID.ToString(),r.ID,'/'))
      From   YourTable r
      Join   cteP p on r.parent_id  = p.ID)
Select Lvl   = HierID.GetLevel()
      ,ID
      ,parent_id
      ,Name  
 From cteP A
 Order By A.HierID

结果

Lvl ID  parent_id   Name
1   1   NULL        P1
1   2   NULL        P2
2   3   2           P2-1
2   4   2           P2-2
2   5   2           P2-3
3   6   5           P2-3-1
3   7   5           P2-3-2
1   8   NULL        P3
2   9   8           P3-1

只是为了好玩,如果我将 @Top 设置为 2,结果将是

Lvl ID  parent_id   Name
1   2   NULL        P2
2   3   2           P2-1
2   4   2           P2-2
2   5   2           P2-3
3   6   5           P2-3-1
3   7   5           P2-3-2