如何从父子层次结构表创建查询

Posted

技术标签:

【中文标题】如何从父子层次结构表创建查询【英文标题】:How to create query from parent child hierarchy table 【发布时间】:2018-01-21 12:18:29 【问题描述】:

如何编写查询以将具有父/子层次结构的表转换为我的层次结构级别位于单独列中的表?

我在 SQL Server 中有一个表(来自 SAP,我相信没有进行任何更改),它为我提供了包含我的利润中心的组结构。表的结构是典型的父子层次结构,如下图。

Parent  |  Child  
--------+--------
S-1     |  S-11  
S-1     |  S-12  
S-1     |  S-13  
S-1     |  S-14  
S-1     |  S-15  
S-11    |  S-111  
S-11    |  S-112  
..      |  ..  
S-152   |  S-1521  
S-152   |  S-1522  
S-1522  |  S-15221  

我想写一个查询,给我一个表,我可以在其中找到每个组的级别 1、级别 2、级别 3 等。团体。级别 1 是***(并且将始终存在),级别 2 是下一个级别。可以有无限的关卡,但此时使用的***别为 8 级。

Group   | Level 1   | Level 2   | Level 3   | Level 4   | Level 5  
--------+-----------+-----------+-----------+-----------+---------
S-111   | S-1       | S-11      | S-111     |           |  
S-11211 | S-1       | S-11      | S-112     | S-1121    | S-11211  
S-1211  | S-1       | S-12      | S-121     | S-1211    | 
S-1212  | S-1       | S-12      | S-121     | S-1212    | 
S-122   | S-1       | S-12      | S-122     |           |     
S-123   | S-1       | S-12      | S-123     |           |
S-1311  | S-1       | S-13      | S-131     | S-1311    | 
S-1312  | S-1       | S-13      | S-131     | S-1312    | 
S-1321  | S-1       | S-13      | S-132     | S-1321    | 
S-141   | S-1       | S-14      | S-141     |           |
S-151   | S-1       | S-15      | S-151     |           |
S-1521  | S-1       | S-15      | S-152     | S-1521    | 
S-15221 | S-1       | S-15      | S-152     | S-1522    | S-15221  

我已使用 Google 和此页面找到最终解决方案,但尚未找到。但我设法做到了这一点:

WITH MyTest as  
(  
    SELECT 
        P.PRCTR_CHILD, P.PRCTR_PARENT, 
        CAST(P.PRCTR_CHILD AS VARCHAR(MAX)) AS Level  
    FROM 
        [IBM_PA_Integration].[dbo].[PRCTRHIER] AS P  
    WHERE 
        P.PRCTR_PARENT = 'S-1000' –- S-1000 is a division  

    UNION ALL  

    SELECT 
        P1.PRCTR_CHILD, P1.PRCTR_PARENT, 
        CAST(P1.PRCTR_CHILD AS VARCHAR(MAX)) + ', ' + M.Level  
    FROM 
        [IBM_PA_Integration].[dbo].[PRCTRHIER] AS P1  
    INNER JOIN 
        MyTest M ON M.PRCTR_CHILD = P1.PRCTR_PARENT  
)  
SELECT *   
FROM MyTest  
WHERE PRCTR_PARENT  = 'FS2004' –- FS2004 is the level top level / level above S-1000  

【问题讨论】:

您需要使用递归 cte,然后对结果进行动态支点。 【参考方案1】:

如果您有固定或有限数量的级别,您可能不需要 DYNAMIC SQL。 “解析”路径可以用一点XML来完成。

考虑以下几点:

示例:

Declare @YourTable Table ([Parent] varchar(50),[Child] varchar(50))
Insert Into @YourTable Values 
 (null ,'S-1')
,('S-1','S-11')
,('S-1','S-12')
,('S-1','S-13')
,('S-1','S-14')
,('S-1','S-15')
,('S-11','S-111')
,('S-11','S-112')

;with cteP as (
      Select Child
            ,Parent 
            ,PathID = cast(Child as varchar(500))
      From   @YourTable
      Where  Parent is Null
      Union  All
      Select Child  = r.Child
            ,Parent = r.Parent 
            ,PathID = cast(p.PathID+','+cast(r.Child as varchar(25)) as varchar(500))
      From   @YourTable r
      Join   cteP p on r.Parent  = p.Child)
Select [Group] = Child
      ,B.*
 From  cteP A
 Cross Apply (
                Select Level1 = xDim.value('/x[1]','varchar(max)')
                      ,Level2 = xDim.value('/x[2]','varchar(max)')
                      ,Level3 = xDim.value('/x[3]','varchar(max)')
                      ,Level4 = xDim.value('/x[4]','varchar(max)')
                      ,Level5 = xDim.value('/x[5]','varchar(max)')
                From  (Select Cast('<x>' + replace(PathID,',','</x><x>')+'</x>' as xml) as xDim) as X 
             ) B
  Order By PathID

退货

【讨论】:

谢谢。该解决方案对我有用,并为我提供了我希望的结构。 @DickTaid81 很高兴它有帮助 @JohnCappelletti 是否可以让关卡列动态化?那么在您的示例中,级别 4 和级别 5 不会出现,因为所有值都为空? @jvels 不采用这种方法... SQL Server 在设计上是声明性的。获得动态列的唯一方法是使用动态 SQL。 @Learnings 这是许多可能的解决方案中的一种。实际上,我更喜欢 2016+ 的 JSON 方法(看起来更干净)。我建议您发布一个问题,以便您可以查看其他一些可能更适合您需求的选项。

以上是关于如何从父子层次结构表创建查询的主要内容,如果未能解决你的问题,请参考以下文章

NSManagedObject CoreData 中的父子层次结构

使用 Python sqlparse 获取查询树/层次结构

Hive - 将层次结构表展平为级别

连接两个层次查询以形成更大的层次结构

如何使用物料清单的父子记录创建简单的数据关系

优化 CTE 以在父子层次结构的某个级别返回后代