【发布时间】:2021-11-30 12:50:18
【问题描述】:
我在 SQL Server 的产品层次结构中有一个基于树的 SKU 结构。最低级别的 SKU 永远只有值(这些是消费值)。然后我想在每个级别上生成层次结构的聚合。
这是示例表结构:
| Id | ParentId | Name | Volume | IsSku |
|---|---|---|---|---|
| 1 | -1 | All | 0 | 0 |
| 2 | 1 | Cat A | 0 | 0 |
| 3 | 1 | Cat B | 0 | 0 |
| 4 | 2 | Cat A.1 | 0 | 0 |
| 5 | 2 | Cat A.2 | 0 | 0 |
| 6 | 3 | Cat B.1 | 0 | 0 |
| 7 | 3 | Cat B.2 | 0 | 0 |
| 8 | 4 | SKU1 | 10 | 1 |
| 9 | 4 | SKU2 | 5 | 1 |
| 10 | 5 | SKU3 | 7 | 1 |
| 11 | 5 | SKU4 | 4 | 1 |
| 12 | 6 | SKU1 | 10 | 1 |
| 13 | 6 | SKU2 | 5 | 1 |
| 14 | 7 | SKU3 | 9 | 1 |
| 15 | 7 | SKU4 | 7 | 1 |
我需要一个从 sku 级别 (IsSku=1) 开始的查询,然后进行处理,对 SKU 求和,并将产品类别级别的总和进行汇总,以获得累计运行总计。
我已经看到几个查询,其中在层次结构中存在递归求和,其中每个级别都已经有值,但我需要一个从具有值的最低级别开始并在向上移动时递归计算总和的查询。
我正在尝试这些,但它们看起来主要是对分层数据进行求和,其中每个节点已经有一个值(在我的例子中是卷)。我需要从最低级别开始,随着层次结构的上升,将聚合向上进行。我试图用我的数据来模拟这些帖子中的答案,但到目前为止我的数据设置并不成功。
查询的输出应该是这样的:
| Id | ParentId | Name | Volume | IsSku |
|---|---|---|---|---|
| 1 | -1 | All | 54 | 0 |
| 2 | 1 | Cat A | 26 | 0 |
| 3 | 1 | Cat B | 28 | 0 |
| 4 | 2 | Cat A.1 | 15 | 0 |
| 5 | 2 | Cat A.2 | 11 | 0 |
| 6 | 3 | Cat B.1 | 12 | 0 |
| 7 | 3 | Cat B.2 | 16 | 0 |
| 8 | 4 | SKU1 | 10 | 1 |
| 9 | 4 | SKU2 | 5 | 1 |
| 10 | 5 | SKU3 | 7 | 1 |
| 11 | 5 | SKU4 | 4 | 1 |
| 12 | 6 | SKU1 | 10 | 1 |
| 13 | 6 | SKU2 | 2 | 1 |
| 14 | 7 | SKU3 | 9 | 1 |
| 15 | 7 | SKU4 | 7 | 1 |
我从递归 CTE 开始.
这是我的 CTE 的开始:
DECLARE @tblData TABLE
(
[ID] INT NOT NULL,
[ParentId] INT NULL,
[Name] varchar(50) NOT NULL,
[Volume] int NOT NULL,
[IsSku] bit
)
INSERT INTO @tblData
VALUES
(1,-1,'All',0,0)
,(2,1,'Cat A',0,0)
,(3,1,'Cat B',0,0)
,(4,2,'Cat A.1',0,0)
,(5,2,'Cat A.2',0,0)
,(6,3,'Cat B.1',0,0)
,(7,3,'Cat B.2',0,0)
,(8,4,'SKU1',10,1)
,(9,4,'SKU2',5,1)
,(10,5,'SKU3',7,1)
,(11,5,'SKU4',4,1)
,(12,6,'SKU1',10,1)
,(13,6,'SKU2',5,1)
,(14,7,'SKU3',7,1)
,(15,7,'SKU4',4,1)
;WITH cte AS (
SELECT
a.ID
,a.ParentID
,a.Name
,a.Volume
,CAST('/' + cast(ID as varchar) + '/' as varchar) Node
,0 AS level
,IsSku
FROM @tblData AS a
WHERE a.ParentID = -1
UNION ALL
SELECT
b.ID
,b.ParentID
,b.Name
,b.Volume
,CAST(c.Node + CAST(b.ID as varchar) + '/' as varchar)
,level = c.level + 1
,b.IsSku
FROM @tblData AS b
INNER JOIN cte c
ON b.ParentId = c.ID
)
SELECT c1.ID, c1.ParentID, c1.Name, c1.Node
,ISNULL(SUM(c2.Volume),0)
FROM cte c1
LEFT OUTER JOIN cte c2
ON c1.Node <> c2.Node
AND LEFT(c2.Node, LEN(c1.Node)) = c1.Node
GROUP BY c1.ID, c1.ParentID, c1.Name, c1.Node
感谢任何帮助!
【问题讨论】:
-
你能包括你目前的查询吗?
-
我不太明白预期的结果:例如,
ID=15在样本中有Volume=4,但在输出中有Volume=7? -
@Charlieface,我的错。我修复了源值。
-
@Stu,我用我的原始起始数据、cte 和查询进行了更新。
-
@DaleK,感谢您的反馈。我添加了一些我看过的其他帖子来尝试模仿。
标签: sql sql-server tsql common-table-expression recursive-query