I have a Table TestPoolCalc, I need to show current node amount + sum of below top level Childs calculated amount. Please see the expected output
Table Script and Data
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
Way I tried
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
Expected output
# | PoolID (A) | Amount (B) | Calculated Amount (C) |
---|---|---|---|
1 | Pool 1 | NULL | -75000 B1+C2+C7+C8 |
2 | Pool 1.1 | NULL | -50000 B2+C3+C6 |
3 | Pool 1.1.1 | NULL | -25000 B3+C4+C5 |
4 | Pool 1.1.1.1 | -12500.00 | -12500 B4 |
5 | Pool 1.1.1.2 | -12500.00 | -12500 B5 |
6 | Pool 1.1.2 | -25000.00 | -25000 B6 |
7 | Pool 1.2 | 25000.00 | 25000 B7 |
8 | Pool 1.3 | -50000.00 | -50000 B8 |
9 | Pool 2 | NULL | 75000 B9+C10+C11+C12 |
10 | Pool 2.1 | NULL | 0 B10 |
11 | Pool 2.2 | NULL | 0 B11 |
12 | Pool 2.3 | 75000 | 75000 B12 |
Using your test data:
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
For each node, i gather it and all the children under it. By keeping the PoolID as main, it becomes very easy to gather the final result, although, this code does traverse levels multiple times which can have some performance implications.
Output:
Main | Total |
---|---|
Pool 1 | -75000 |
Pool 1.1 | -50000 |
Pool 1.1.1 | -25000 |
Pool 1.1.1.1 | -12500 |
Pool 1.1.1.2 | -12500 |
Pool 1.1.2 | -25000 |
Pool 1.2 | 25000 |
Pool 1.3 | -50000 |
Pool 2 | 75000 |
Pool 2.1 | 0 |
Pool 2.2 | 0 |
Pool 2.3 | 75000 |
ROOT | 0 |
You can always remove the ROOT if you're not interested in it.