Reputation: 13
I have a table with around 80000 records. Here is an example:
startyear | division | account | budget | forecast |
---|---|---|---|---|
2021 | 40 | 4100 | 5122952,22 | 0,012306656 |
2022 | 40 | 4100 | 0 | 0,011424198 |
2023 | 40 | 4100 | 0 | 0,010431491 |
2024 | 40 | 4100 | 0 | 0,009311863 |
2025 | 40 | 4100 | 0 | 0,008324122 |
2026 | 40 | 4100 | 0 | 0,007763793 |
2027 | 40 | 4100 | 0 | 0,007557735 |
2028 | 40 | 4100 | 0 | 0,007357883 |
2029 | 40 | 4100 | 0 | 0,007160051 |
2030 | 40 | 4100 | 0 | 0,006953345 |
2031 | 40 | 4100 | 0 | 0,006737952 |
2032 | 40 | 4100 | 0 | 0,006535297 |
2033 | 40 | 4100 | 0 | 0,006364179 |
2034 | 40 | 4100 | 0 | 0,006213237 |
2035 | 40 | 4100 | 0 | 0,006085724 |
2036 | 40 | 4100 | 0 | 0,005944279 |
2037 | 40 | 4100 | 0 | 0,005758285 |
2038 | 40 | 4100 | 0 | 0,005559474 |
2039 | 40 | 4100 | 0 | 0,005360105 |
2040 | 40 | 4100 | 0 | 0,005163794 |
2041 | 40 | 4100 | 0 | 0,004972228 |
I'm trying to calculate a new column starting with the budget from line 1. So year 2021 will be the same. the first calculation is correct. But the rest of the calculation ignores the changes before. This is the code:
WITH cte AS (
SELECT startyear, division, account, forecast, SUM(budget) AS asum
FROM @table
GROUP BY startyear,
division,
account,
forecast
), cteRanked AS (
SELECT cte.startyear,
cte.division,
cte.account,
cte.forecast,
cte.asum AS asum
FROM cte
)
SELECT c1.startyear,
c1.division,
c1.account,
c1.forecast,
c1.asum , ISNULL((SELECT SUM(c2.asum)*c1.forecast
FROM cteRanked c2
WHERE c1.startyear > 2021
AND c2.startyear < c1.startyear
AND c2.division = c1.division
AND c2.account = c1.account), c1.asum) AS Bud
FROM cteRanked c1
ORDER BY c1.division, c1.account, c1.startyear
Gives this result:
startyear | division | account | forecast | budget | result | correct |
---|---|---|---|---|---|---|
2021 | 40 | 4100 | 0,012306656 | 5122952,22 | 5122952,22 | 5122952,22 |
2022 | 40 | 4100 | 0,011424198 | 0 | 58525,62051 | 58525,62 |
2023 | 40 | 4100 | 0,010431491 | 0 | 53440,02998 | 54050,54 |
2024 | 40 | 4100 | 0,009311863 | 0 | 47704,22923 | 48752,52 |
2025 | 40 | 4100 | 0,008324122 | 0 | 42644,07928 | 43987,00 |
2026 | 40 | 4100 | 0,007763793 | 0 | 39773,54059 | 41367,57 |
As you can see this query does not cumulate the results when the query runs. Anyone have any ideas?
Upvotes: 1
Views: 787
Reputation: 2602
While your post is lacking some vital information...I don't necessarily blame you because it's a difficult problem to both explain and to solve.
It looks like you're basically trying to come up with a compounding interest calculator. Except in this case, the rate changes every year.
To calculate the PRODUCT aggregate of your forecasts, I found this blog post: https://blog.jooq.org/2018/09/21/how-to-write-a-multiplication-aggregate-function-in-sql/
It just required a very tiny bit of tweaking.
This is my answer:
DECLARE @StartingYear int = 2021,
@StartingBudget decimal(12, 2);
SELECT @StartingBudget = yt.budget
FROM #YourTable yt
WHERE yt.startyear = @StartingYear
SELECT yt.startyear, yt.division, yt.account, yt.budget, yt.forecast, YearBudget = yt.budget, PrevYearDiff = yt.budget
FROM #YourTable yt
WHERE yt.startyear = @StartingYear
UNION ALL
SELECT x.startyear, x.division, x.account, x.budget, x.forecast
, YearBudget = CONVERT(decimal(10,2), x.SumProdBudget)
, PrevYearDiff = CONVERT(decimal(10,2), x.SumProdBudget - LAG(x.SumProdBudget,1,@StartingBudget) OVER (ORDER BY x.startyear))
FROM (
SELECT yt.startyear, yt.division, yt.account, yt.budget, yt.forecast
, SumProdBudget = EXP(SUM(LOG(1+yt.forecast)) OVER (ORDER BY yt.startyear)) * @StartingBudget
FROM #YourTable yt
WHERE yt.startyear > @StartingYear
) x
Returns:
| startyear | division | account | budget | forecast | YearBudget | PrevYearDiff |
|-----------|----------|---------|------------|-------------|------------|--------------|
| 2021 | 40 | 4100 | 5122952.22 | 0.012306656 | 5122952.22 | 5122952.22 |
| 2022 | 40 | 4100 | 0.00 | 0.011424198 | 5181477.84 | 58525.62 |
| 2023 | 40 | 4100 | 0.00 | 0.010431491 | 5235528.38 | 54050.54 |
| 2024 | 40 | 4100 | 0.00 | 0.009311863 | 5284280.90 | 48752.52 |
| 2025 | 40 | 4100 | 0.00 | 0.008324122 | 5328267.90 | 43987.00 |
| 2026 | 40 | 4100 | 0.00 | 0.007763793 | 5369635.47 | 41367.57 |
The key to this whole thing is this line:
SELECT SumProdBudget = EXP(SUM(LOG(1+yt.forecast)) OVER (ORDER BY yt.startyear)) * @StartingBudget
This is saying to return a running product of all previous forecasts, then multiply that by the original budget. This will produce the budget for each year, technically based on the budget of the previous year.
Then once you have that, I stuck it in a sub-query to find the difference between the year and its previous year.
IF OBJECT_ID('tempdb..#YourTable','U') IS NOT NULL DROP TABLE #YourTable; --SELECT * FROM #YourTable
CREATE TABLE #YourTable (
startyear int NOT NULL,
division int NOT NULL,
account int NOT NULL,
budget decimal(12, 2) NOT NULL,
forecast decimal(10, 9) NOT NULL,
);
INSERT INTO #YourTable (startyear, division, account, budget, forecast)
VALUES (2021, 40, 4100, 5122952.22, 0.012306656)
, (2022, 40, 4100, 0 , 0.011424198)
, (2023, 40, 4100, 0 , 0.010431491)
, (2024, 40, 4100, 0 , 0.009311863)
, (2025, 40, 4100, 0 , 0.008324122)
, (2026, 40, 4100, 0 , 0.007763793)
, (2027, 40, 4100, 0 , 0.007557735)
, (2028, 40, 4100, 0 , 0.007357883)
, (2029, 40, 4100, 0 , 0.007160051)
, (2030, 40, 4100, 0 , 0.006953345)
, (2031, 40, 4100, 0 , 0.006737952)
, (2032, 40, 4100, 0 , 0.006535297)
, (2033, 40, 4100, 0 , 0.006364179)
, (2034, 40, 4100, 0 , 0.006213237)
, (2035, 40, 4100, 0 , 0.006085724)
, (2036, 40, 4100, 0 , 0.005944279)
, (2037, 40, 4100, 0 , 0.005758285)
, (2038, 40, 4100, 0 , 0.005559474)
, (2039, 40, 4100, 0 , 0.005360105)
, (2040, 40, 4100, 0 , 0.005163794)
, (2041, 40, 4100, 0 , 0.004972228);
Upvotes: 1