T-SQL - Rolling 12 Month Average - sql

I would like to return rolling 12 month averages for each month in a resulting dataset but am not sure how I can do this.
I thought the following script would work:
DECLARE #StartDate as datetime
DECLARE #EndDate as datetime
SET #StartDate = '01/04/2011'
SET #EndDate = getdate()
select x.FinYear, x.FinMonth, x.MonthText, avg(TimeSeconds) [AverageTimeSeconds]
from times x
where (x.TimeOfCall >= #StartDate and x.TimeOfCall < #EndDate)
group by x.FinYear, x.FinMonth, x.MonthText
order by x.FinYear, x.FinMonth
but it only returns the monthly averages, how do I get the 12 month average leading up to each of the months between the start and end date.
The resulting dataset I am looking for is as follows:
Fin Year Fin Month Month Text Avg Time Seconds R12M Avg Seconds
2015/16 01 Apr 100 101
2015/16 02 May 95 98
2015/16 03 Jun 103 100
2015/16 04 Jul 110 100
2015/16 05 Aug 100 100
2015/16 06 Sep 90 97
2015/16 07 Oct 93 97
2015/16 08 Nov 98 100
2015/16 09 Dec 80 98
2015/16 10 Jan 88 98
2015/16 11 Feb 100 98
2016/17 12 Mar 115 100
2016/17 01 Apr 105 100
2016/17 02 May 98 100
2016/17 03 Jun 95 98
2016/17 04 Jul 102 98
2016/17 05 Aug 109 99
2016/17 06 Sep 104 100
2016/17 07 Oct 98 98
2016/17 08 Nov 99 97
2016/17 09 Dec 90 97
the rolling 12 month average is not an average of the monthly averages but an average of the 12 months leading up to the month in question. So January 2017 would be the average of 01 February 2016 - 31 January 2017 and October 2016 would be 01 November 2015 to 31 October 2016.
I hope you can help :-) .

If you have data for every month, then the following calculates the average over the preceding 12 months (note this is the overall average, not the average of the monthly averages):
select x.FinYear, x.FinMonth, x.MonthText, avg(TimeSeconds)as [AverageTimeSeconds],
(sum(sum(TimeSeconds)) over (order by x.FinYear, x.FinMonth rows between 11 preceding and current row) /
sum(count(*)) over (order by x.FinYear, x.FinMonth rows between 11 preceding and current row)
) as avg_12month
from times x
where x.TimeOfCall >= #StartDate and x.TimeOfCall < #EndDate
group by x.FinYear, x.FinMonth, x.MonthText
order by x.FinYear, x.FinMonth;
Note: The where clause affects the 12-month look-back period. In other worse, the look-back will not include months before this period.

Related

SQL - SUM and grouping

I have a following table:
ITEM
Date
VALUE
START DATE
END DATE
1
01 Jan 2023
15
01 Jan 2023
02 Jan 2023
1
02 Jan 2023
20
02 Jan 2023
03 Jan 2023
1
03 Jan 2023
25
03 Jan 2023
04 Jan 2023
1
04 Jan 2023
40
04 Jan 2023
05 Jan 2023
2
01 Jan 2023
30
01 Jan 2023
02 Jan 2023
2
02 Jan 2023
20
02 Jan 2023
03 Jan 2023
2
03 Jan 2023
10
03 Jan 2023
04 Jan 2023
2
04 Jan 2023
40
04 Jan 2023
05 Jan 2023
From here I need to have calculated sum of all values for every given row/date that are within dates in Start and End Date columns (boundaries included), so it is grouped by item and per date.
ITEM
Date
VALUE_SUM
1
01 Jan 2023
35
1
02 Jan 2023
45
1
03 Jan 2023
65
1
04 Jan 2023
40
2
01 Jan 2023
50
2
02 Jan 2023
30
2
03 Jan 2023
50
2
04 Jan 2023
40
Thanks for your help!
A simple way is to use a correlated subquery to do the calculation:
select item, date,
(select sum(value) from table t2
where t2.item = t1.item
and t2.date between t1.start_date and t1.end_date)
from table t1
Assuming you are only working with one month of data - one option could be to extract the day value from each date and then sum up each value while grouping by day.
This can be done by firstly creating a new variable in your dataset to store the day value:
alter table dataset add day int;
Values can then be extracted:
update dataset set day=extract(day from date);
Then, it is a matter of grouping the values by day:
select day, sum(value) as value_sum from dataset group by day order by day;

Indexing Time in Redshift

i have a dataset with that has sales by month and a column for when an promotion happens for a number of products.
i want to index the months so that i can compare the different products over a pre and post 12m period easily
this is the data i have
Date
sales.
Promo?
Jan 21
100
Feb 21
110.
Mar 21
100.
apr 21
110.
may 21
90.
jun 21
100.
jul 21
120.
aug 21
140.
X
sep 21
100.
oct 21
90.
nov 21
100.
dec 21
120.
jan 22
110.
feb 22
100
this is what i want
can someone tell me how to do this in redshift?
Date
sales.
Promo?
month index
Jan 21
100
-7.
Feb 21
110.
-6
Mar 21
100.
-5
apr 21
110.
-4
may 21
90.
-3
jun 21
100.
-2
jul 21
120.
-1
aug 21
140.
X
0
sep 21
100.
1
oct 21
90.
2
nov 21
100.
3
dec 21
120.
4
jan 22
110.
5
feb 22
100
6

How to get the first and the last value in a column per each sequence with the same value

I would like to get the first and the last value in the column Status1 of each sequence of the same value!
This is an example of my table:
time Status1 Eficiencia Lote
----------------------------------------------------
2020 06 14 18:03:48.457 70 80 95
2020 06 14 18:04:47.693 70 80 95
2020 06 14 18:06:58.203 55 80 95
2020 06 14 18:08:19.900 55 80 95
2020 06 14 18:09:45.537 55 80 95
2020 06 14 18:10:06.670 100 80 13
2020 06 14 18:10:27.297 100 80 13
2020 06 14 18:10:31.810 100 80 13
2020 06 14 18:10:43.187 100 80 13
2020 06 14 18:11:30.303 55 80 14
2020 06 14 18:12:07.563 55 80 14
2020 06 14 18:18:54.997 55 80 14
I tried this but using this I didn't get by each sequence but in the hole table!
;with cte as
(
select
*,
RnAsc = row_number() over (partition by [Status1] order by time),
RnDesc = row_number() over (partition by [Status1] order by time desc)
from
[VALORES_DB].[dbo].[OEE_TESTE]
)
select time, [Status1], Eficiencia, Lote, Status1
from cte
where RnAsc = 1 or RnDesc = 1
I would like to get the follow:
time Status1 Eficiencia Lote
------------------------------------------------------
2020 06 14 18:03:48.457 70 80 95
2020 06 14 18:04:47.693 70 80 95
2020 06 14 18:06:58.203 55 80 95
2020 06 14 18:09:45.537 55 80 95
2020 06 14 18:10:06.670 100 80 13
2020 06 14 18:10:43.187 100 80 13
2020 06 14 18:11:30.303 55 80 14
2020 06 14 18:18:54.997 55 80 14
I would suggest lag() and lead():
select t.*
from (select t.*,
lag(status1) over (order by time) as prev_status1,
lead(status1) over (order by time) as next_status1
from t
) t
where (prev_status1 is null or prev_status1 <> status1) or
(next_status1 is null or next_status1 <> status1);
These comparisons determine where the value changes -- which is really what you are asking for.

SQL Query to group by month and display individual month sum for a record

I'm trying to sum product codes with a particular description as total products sold in a month over the years.
The two table used are:
CREATE TABLE product (
prod_code NUMBER(3) NOT NULL,
prod_description VARCHAR2(75) NOT NULL,
prod_points NUMBER(2) NOT NULL
);
CREATE TABLE product_sale (
sale_no NUMBER(8) NOT NULL,
sale_datetime DATE NOT NULL,
sale_location VARCHAR2(100) NOT NULL,
prod_code NUMBER(3) NOT NULL,
officer_id NUMBER(8) NOT NULL,
);
The date format is in 'DD-MON-YYYY HH12:MI PM'.
So far I'm able to formulate this:
select
d.prod_description,
extract(month from sale_datetime) as mon,
count(d.prod_code) as count
from product d
join product_sale o on d.prod_code = o.prod_code
group by d.prod_description, extract(month from sale_datetime);
order by d.prod_code;
How do I separate the count as different month columns and get the sum of count in a separate column?
I would just use conditional aggregation:
select d.prod_description, count(*) as total,
sum(case when extract(month from sale_datetime) = 1 then 1 else 0 end) as jan,
sum(case when extract(month from sale_datetime) = 2 then 1 else 0 end) as feb,
. . .
from product d join
product_sale o
on d.prod_code = o.prod_code
group by d.prod_code, d.prod_description
order by d.prod_code;
Note that for the ordering, prod_code needs to be in the group by -- or you need to use an aggregation function such as order by min(d.prod_code).
If you want a separate row for totals, then use grouping sets:
group by grouping sets ( (d.prod_code, d.prod_description), () )
So the JAN column should contain the counts for January of every year.
I will assume that in addition to the horizontal sum, you want a vertical sum.
First you need to aggregate at different levels, then PIVOT to get the data from different rows into different columns of the same row.
To aggregate at different levels, Oracle provides GROUP BY extensions such as CUBE:
select prod_code, prod_description,
nvl(extract(month from sale_datetime),0) mon,
count(*) cnt
from product join product_sale using(prod_code)
group by cube((prod_code, prod_description), extract(month from sale_datetime))
Now you can pivot:
select * from (
select prod_code, prod_description,
nvl(extract(month from sale_datetime),0) mon,
count(*) cnt
from product join product_sale using(prod_code)
group by cube((prod_code, prod_description), extract(month from sale_datetime))
)
pivot(max(cnt) for mon in(
0 sum,1 jan,2 feb,3 mar,4 apr,5 may,6 jun,7 jul,8 aug,9 sep,10 oct,11 nov,12 dec
))
order by prod_description;
PROD_CODE PROD_DESCRIPTION SUM JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
1 1 516 61 57 62 60 62 30 31 31 30 31 30 31
2 2 516 61 57 62 60 62 30 31 31 30 31 30 31
3 3 516 61 57 62 60 62 30 31 31 30 31 30 31
4 4 516 61 57 62 60 62 30 31 31 30 31 30 31
5 5 516 61 57 62 60 62 30 31 31 30 31 30 31
6 6 516 61 57 62 60 62 30 31 31 30 31 30 31
7 7 516 61 57 62 60 62 30 31 31 30 31 30 31
8 8 516 61 57 62 60 62 30 31 31 30 31 30 31
9 9 516 61 57 62 60 62 30 31 31 30 31 30 31
4644 549 513 558 540 558 270 279 279 270 279 270 279
This is a simplified solution, for example I don't label the vertical sum row at the bottom. For a complete solution and explanation of this technique, see https://stewashton.wordpress.com/2016/07/18/spreadsheet-like-totals-and-subtotals/

How to get the data in decline pattern/trending using Oracle SQL?

How can I get the result only for those monthly data in decline pattern/trending ?
And the data as below;
ID JAN FEB MAR APR MAY JUN
112 50 45 40 35 30 20
113 30 30 30 30 30 30
114 20 25 20 20 20 20
115 45 50 60 60 30 30
Expected output ;
ID JAN FEB MAR APR MAY JUN
112 50 45 40 35 30 20
115 45 50 60 60 30 30
Thanks !
SELECT *
FROM your_table
WHERE JAN > JUN
or
SELECT *
FROM your_table
WHERE JAN > FEB
AND FEB > MAR
AND MAR > APR
AND APR > MAY
AND MAY > JUN
It appears that what you're looking for is
SELECT *
FROM SOME_TABLE
WHERE JAN > FEB OR
FEB > MAR OR
MAR > APR OR
APR > MAY OR
MAY > JUN
Best of luck.