如何从父子层次结构表创建查询
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 方法(看起来更干净)。我建议您发布一个问题,以便您可以查看其他一些可能更适合您需求的选项。以上是关于如何从父子层次结构表创建查询的主要内容,如果未能解决你的问题,请参考以下文章