Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, hanu.

Asked: March 01, 2017 - 3:50 am UTC

Last updated: March 02, 2017 - 1:49 pm UTC

Version: 11g

Viewed 10K+ times! This question is

You Asked

Hi Sir - Trying to calculate the rolling sum or so.
When
create table tbl1 ( year number, month varchar2(3), col1 varchar2(10), col2 varchar2 (20), amount number)
I need to list the values of col1, col2 along with the value as the below calculation (I believe it is rolling sum)
{ SUM(amount) for year , month (Ex: 2016, 02) , col1, col2} / {sum (amount) for past 12 months Mar 15 - Feb 16}. Trying to do it in a single SQL or using any analytical functions or so.

create table tbl1 ( year number, month varchar2(3), col1 varchar2(10), col2 varchar2 (20), amount number);



insert into tbl1 values (2015, '1', 'abc','temp123',7259.1);

insert into tbl1 values (2015, '1', 'def','temp123',7259.1);

insert into tbl1 values (2015, '1', 'def','temp345',729.1);

insert into tbl1 values (2015, '3', 'abc','temp35',659);


insert into tbl1 values (2014, '1', 'abc','temp123',259);

insert into tbl1 values (2014, '2', 'def','temp123',7259.45);

insert into tbl1 values (2014, '1', 'def','temp345',874.8);

insert into tbl1 values (2013, '2', 'VAL2','temp123',6547.8);

insert into tbl1 values (2013, '3', 'VAL2','temp345',862.0);

insert into tbl1 values (2013, '3', 'VAL3','temp345',659);

hope I am clear enough

with LiveSQL Test Case:

and Chris said...

You can get a rolling sum (or count, or whatever) using the window clause of analytics. This specifies a number of rows or range of values to include in the calculation.

You don't know how many rows there will be in the past 12 months. So you need to use range. You use this to state an offset of values to include from your current row.

Your "dates" are separate year and month values. Calculating the offset using these is tricky. It's much easier to convert them to a date first. Then you can specify the number of months to look back (or forward) as an interval.

This gives you:

create table tbl1 ( 
  year number, month varchar2(3), col1 varchar2(10), col2 varchar2 (20), amount number
);

insert into tbl1 values (2015, '1', 'abc','temp123',7259.1);
insert into tbl1 values (2015, '1', 'def','temp123',7259.1);
insert into tbl1 values (2015, '1', 'def','temp345',729.1);
insert into tbl1 values (2015, '3', 'abc','temp35',659);
insert into tbl1 values (2014, '1', 'abc','temp123',259);
insert into tbl1 values (2014, '2', 'def','temp123',7259.45);
insert into tbl1 values (2014, '1', 'def','temp345',874.8);
insert into tbl1 values (2013, '2', 'VAL2','temp123',6547.8);
insert into tbl1 values (2013, '3', 'VAL2','temp345',862.0);
insert into tbl1 values (2013, '3', 'VAL3','temp345',659);

select t.*, 
       sum(amount) over (
         order by to_date(year || lpad(month, 2, '0') || '01', 'yyyymmdd')
         range between interval '12' month preceding and current row
       ) sm_12_months
from tbl1 t
order by to_date(year || lpad(month, 2, '0') || '01', 'yyyymmdd');

YEAR   MONTH  COL1  COL2     AMOUNT    SM_12_MONTHS  
2,013  2      VAL2  temp123  6,547.8   6,547.8       
2,013  3      VAL2  temp345  862       8,068.8       
2,013  3      VAL3  temp345  659       8,068.8       
2,014  1      abc   temp123  259       9,202.6       
2,014  1      def   temp345  874.8     9,202.6       
2,014  2      def   temp123  7,259.45  16,462.05     
2,015  1      abc   temp123  7,259.1   23,640.55     
2,015  1      def   temp123  7,259.1   23,640.55     
2,015  1      def   temp345  729.1     23,640.55     
2,015  3      abc   temp35   659       15,906.3


You can read more about this at:

http://www.oracle.com/technetwork/issue-archive/2013/13-mar/o23sql-1906475.html

Or watch Connor's videos at:

https://www.youtube.com/watch?v=dovPI166tcs
https://www.youtube.com/watch?v=oeRZFZUXs1U

PS - when sharing LiveSQL links, you can't just copy-paste the URL from your session! You need to save it as a public script first. Then share the public URL.

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

missing

Gh.., March 01, 2017 - 12:30 pm UTC

"I need to list the values of col1, col2 along with the value as the below calculation "

so, missed is the "partition by" clause on col1 and col2
Chris Saxon
March 01, 2017 - 2:26 pm UTC

That's not how I read that... but the fact you do highlights the importance of clear, precise test cases!

A reader, March 01, 2017 - 2:41 pm UTC

Hi sir, - yes the chance is that we can have same rows with different col1, col2 values in a year and month. also what we are trying to accomplish is get the rolling 12, rolling, rolling 36 for the list of the col1, col2 and year month.rolling 12 = feb 16/ sum (Mar 15 - Feb 16)
rolling 24 = feb 15/ sum (Mar 14 - Feb 15)
rolling 36 = feb 14/ sum (Mar 13 - Feb 14)
can all thihs be done in one sql, then we are trying to sum them up
rolling 12 +rolling 24 + rolling 36. Hope i am clear enough.
Some rows might be in a particular year and month, some might not. hope i am clear enought

Chris Saxon
March 01, 2017 - 2:50 pm UTC

No, I'm not sure what you're looking for! Why do you need to sum them up? Surely rolling 36 months already includes the 24 and 12 month periods?

Please supply the output you expect given the test data in the question.

A reader, March 01, 2017 - 3:12 pm UTC

hi sir - the reason is we need to get the data in the following

rolling 12 = feb 16/ sum (Mar 15 - Feb 16)
rolling 24 = feb 15/ sum (Mar 14 - Feb 15) --> not sure whether this can be called as rolling 24 months or so. Its just that we need to get the SUMMARY PRIOR to 12 months of rolling 12.
rolling 36 = feb 14/ sum (Mar 13 - Feb 14)
after that we need to multiply it with a constant before summing them up.

feb 16/ sum (Mar 15 - Feb 16) * 0.2 + feb 15/ sum (Mar 14 - Feb 15) *0.3
+ feb 14/ sum (Mar 13 - Feb 14)* 0.5


Chris Saxon
March 02, 2017 - 11:41 am UTC

I'm still not sure exactly what you're looking for. Please provide a table showing the OUTPUT you expect given the data you supplied with an explanation of the data. For example, does Mar 16 = 1 March 2016, or 16th March?

What is the value for "Feb 16"?

Anyway, you can give different ranges in your rolling window. e.g. get the sum of the between the 24 and 12 months prior to the current row:

range between interval '24' month preceding and interval '12' month preceding


A reader, March 02, 2017 - 1:20 pm UTC

Hi sir - March 13 stands for March 2013. As the data is at the month level, with out any date.
Chris Saxon
March 02, 2017 - 1:49 pm UTC

And what is the value for "Feb 16"? What does the output look like? e.g.

YEAR MONTH RESULT
2016 FEB XXX <--- what is this value?

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.