我有一个表TestPoolCalc,我需要显示当前节点数量+低于顶级Childs计算数量的总和。请查看预期输出
表格脚本和数据
CREATE TABLE [dbo].[_TestPoolCalc](
[PoolID] [varchar](50) NULL,
[ParentPoolID] [varchar](50) NULL,
[Amount] [numeric](18, 2) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1
', N'ROOT', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.1
', N'Pool 1
', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.1.1
', N'Pool 1.1
', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.1.1.1
', N'Pool 1.1.1
', CAST(-12500.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.1.1.2
', N'Pool 1.1.1
', CAST(-12500.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.1.2
', N'Pool 1.1
', CAST(-25000.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.2
', N'Pool 1
', CAST(25000.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 1.3', N'Pool 1
', CAST(-50000.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 2', N'ROOT', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 2.1', N'Pool 2', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 2.2', N'Pool 2', NULL)
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'Pool 2.3', N'Pool 2', CAST(75000.00 AS Numeric(18, 2)))
GO
INSERT [dbo].[_TestPoolCalc] ([PoolID], [ParentPoolID], [Amount]) VALUES (N'ROOT', NULL, NULL)
GO
我尝试过的方式
WITH p AS (SELECT
a.ParentPoolID, a.PoolID
, CAST(a.PoolID AS VARCHAR(MAX)) AS path
, len(CAST(a.PoolID AS VARCHAR(MAX))) lpath
, a.Amount
FROM _TestPoolCalc a
WHERE a.ParentPoolID = 'Root'
UNION ALL
SELECT
pp.ParentPoolID, pp.PoolID
, p_2.path + '>' + pp.PoolID AS path
, len(p_2.path + '>' + pp.PoolID) lpath
, pp.Amount
FROM _TestPoolCalc pp
JOIN p AS p_2 ON pp.ParentPoolID = p_2.PoolID
)
SELECT PoolID,ParentPoolID, path
,Amount
,isnull((select sum(isnull(p1.Amount,0.0)) from p p1 where left(p1.path,p.lpath) = p.path and p.poolid <> p1.PoolId ),0) CalculatedAmount
FROM p
order by path
预期产量
# | 矿池ID (A) | 金额(B) | 计算金额(C) |
---|---|---|---|
1 | 池1 | 空 | -75000
|
2 | 泳池1.1 | 空 | -50000
|
3 | 矿池1.1.1 | 空 | -25000
|
4 | 矿池1.1.1.1 | -12500.00 | -12500
|
5 | 矿池1.1.1.2 | -12500.00 | -12500
|
6 | 矿池1.1.2 | -25000.00 | -25000
|
7 | 泳池1.2 | 25000.00 | 25000
|
8 | 泳池1.3 | -50000.00 | -50000
|
9 | 泳池2 | 空 | 75000
|
10 | 池2.1 | 空 | 0
|
11 | 泳池2.2 | 空 | 0
|
12 | 泳池2.3 | 75000 | 75000
|
使用您的测试数据:
WITH p AS (
SELECT poolid AS main, t.Amount, t.PoolID AS parent
FROM _TestPoolCalc t
UNION ALL
SELECT p.main, tc.amount, tc.poolid
FROM p
INNER JOIN _TestPoolCalc tc
ON tc.ParentPoolID = p.parent
)
SELECT Main, ISNULL(SUM(Amount),0) AS total
FROM p
GROUP BY Main
对于每个节点,我收集它及其下的所有子节点。通过将 PoolID 保留为主,收集最终结果变得非常容易,尽管此代码确实多次遍历级别,这可能会产生一些性能影响。
输出:
主要 | 总计 |
---|---|
池1 | -75000 |
泳池1.1 | -50000 |
矿池1.1.1 | -25000 |
矿池1.1.1.1 | -12500 |
矿池1.1.1.2 | -12500 |
矿池1.1.2 | -25000 |
泳池1.2 | 25000 |
泳池1.3 | -50000 |
泳池2 | 75000 |
池2.1 | 0 |
泳池2.2 | 0 |
泳池2.3 | 75000 |
根 | 0 |
如果你不感兴趣,你可以随时删除ROOT。