CCP months QUART YEARS GTS
---- ------ ----- ----- ---
CCP1 1 1 2015 5
CCP1 2 1 2015 6
CCP1 3 1 2015
Another method that uses the EXP(SUM(LOG()))
trick and only window functions for the running total (no recursive CTEs or cursors).
Tested at dbfiddle.uk:
WITH
ct AS
( SELECT
ccp, years, quart,
q2 = round(exp(coalesce(sum(log(sum(gts)))
OVER (PARTITION BY ccp
ORDER BY years, quart
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING)
, 0))
, 2) -- round appropriately to your requirements
FROM gts
GROUP BY ccp, years, quart
)
SELECT
g.*,
result = g.gts * b.baseline * ct.q2,
baseline = b.baseline * ct.q2
FROM ct
JOIN gts AS g
ON ct.ccp = g.ccp
AND ct.years = g.years
AND ct.quart = g.quart
CROSS APPLY
( SELECT TOP (1) b.baseline
FROM baseline AS b
WHERE b.ccp = ct.ccp
ORDER BY b.years, b.quart
) AS b
;
How it works:
(CREATE
tables and INSERT
skipped)
1, lets group by ccp, year and quart and calculate the sums:
select ccp, years, quart, q1 = sum(gts) from gts group by ccp, years, quart ; GO
ccp | years | quart | q1 :--- | ----: | ----: | :-------- CCP1 | 2015 | 1 | 18.000000 CCP1 | 2015 | 2 | 8.000000 CCP1 | 2015 | 3 | 6.000000 CCP1 | 2015 | 4 | 9.000000 CCP1 | 2016 | 1 | 12.000000
EXP(LOG(SUM())
trick to calculate the running multiplications of these sums. We use BETWEEEN .. AND -1 PRECEDING
in the window to skip the current values, as these values are only used for the baselines of the next quart.LOG()
and EXP()
. You can experiment with using either ROUND()
or casting to NUMERIC
:with ct as ( select ccp, years, quart, q1 = sum(gts) from gts group by ccp, years, quart ) select ccp, years, quart, -- months, gts, q1, q2 = round(exp(coalesce(sum(log(q1)) OVER (PARTITION BY ccp ORDER BY Years, Quart ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0)),2) from ct ; GO
ccp | years | quart | q2 :--- | ----: | ----: | ---: CCP1 | 2015 | 1 | 1 CCP1 | 2015 | 2 | 18 CCP1 | 2015 | 3 | 144 CCP1 | 2015 | 4 | 864 CCP1 | 2016 | 1 | 7776
gts
so we can multiply each value with the calculated q2
(which gives us the baseline).CROSS APPLY
is merely to get the base baseline for each ccp.numeric(22,6)
instead of rounding to 2 decimal places. The results are the same with the sample but they may differ if the numbers are bigger or not integer:with ct as ( select ccp, years, quart, q2 = cast(exp(coalesce(sum(log(sum(gts))) OVER (PARTITION BY ccp ORDER BY years, quart ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) , 0.0)) as numeric(22,6)) -- round appropriately to your requirements from gts group by ccp, years, quart ) select g.*, result = g.gts * b.baseline * ct.q2, baseline = b.baseline * ct.q2 from ct join gts as g on ct.ccp = g.ccp and ct.years = g.years and ct.quart = g.quart cross apply ( select top (1) baseline from baseline as b where b.ccp = ct.ccp order by years, quart ) as b ; GO
CCP | months | QUART | YEARS | GTS | result | baseline :--- | -----: | ----: | ----: | :------- | :------------ | :----------- CCP1 | 1 | 1 | 2015 | 5.000000 | 25.000000 | 5.000000 CCP1 | 2 | 1 | 2015 | 6.000000 | 30.000000 | 5.000000 CCP1 | 3 | 1 | 2015 | 7.000000 | 35.000000 | 5.000000 CCP1 | 4 | 2 | 2015 | 4.000000 | 360.000000 | 90.000000 CCP1 | 5 | 2 | 2015 | 2.000000 | 180.000000 | 90.000000 CCP1 | 6 | 2 | 2015 | 2.000000 | 180.000000 | 90.000000 CCP1 | 7 | 3 | 2015 | 3.000000 | 2160.000000 | 720.000000 CCP1 | 8 | 3 | 2015 | 2.000000 | 1440.000000 | 720.000000 CCP1 | 9 | 3 | 2015 | 1.000000 | 720.000000 | 720.000000 CCP1 | 10 | 4 | 2015 | 2.000000 | 8640.000000 | 4320.000000 CCP1 | 11 | 4 | 2015 | 3.000000 | 12960.000000 | 4320.000000 CCP1 | 12 | 4 | 2015 | 4.000000 | 17280.000000 | 4320.000000 CCP1 | 1 | 1 | 2016 | 8.000000 | 311040.000000 | 38880.000000 CCP1 | 2 | 1 | 2016 | 1.000000 | 38880.000000 | 38880.000000 CCP1 | 3 | 1 | 2016 | 3.000000 | 116640.000000 | 38880.000000