【问题标题】:Recursive query with parent-child relation具有父子关系的递归查询
【发布时间】:2021-07-18 04:48:12
【问题描述】:

我正在尝试在 SQL Server 中进行递归查询,以分层显示数据。这是表的结构

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

每个产品都有一个父级。 Parent_Id 列包含父级的 id。根产品的 parent_id 为 null。

我想创建一个分层显示产品的 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

我想要将每个产品同级分组,以便每个产品都显示在其直接父级下。

【问题讨论】:

  • 您的代码没有意义。例如,parent_id 声明为 not null,但在示例数据中它是 null

标签: sql sql-server tsql hierarchical-data recursive-query


【解决方案1】:

使用数据类型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

【讨论】:

  • 注意——给定表的结构,hierarchyid 需要及时计算。但!如果您修改应用程序以在数据更改时对其进行维护,您可以立即使用它。
【解决方案2】:

在递归查询中构造路径。以下将其作为具有固定长度 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;

【讨论】:

  • 谢谢你的回答。但我一直在寻找一种在 c# 端不需要大量代码的解决方案。所以最后,约翰的解决方案,它符合我的需要;
  • @THEHOLYSPIRIT。 . .约翰经常想出非常聪明和适当的解决方案。但是,我没有意识到这会在应用程序端造成大量编码。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 2021-12-18
    • 1970-01-01
    • 2013-04-07
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-14
    相关资源
    最近更新 更多