Reputation: 582
We have a table with columns TXN_DATE and NO_OF_TXNS. Below is sample data:
TXN_DATE NO_OF_TXNS
25-AUG-19 0
26-AUG-19 1000
27-AUG-19 1500
28-AUG-19 1800
29-AUG-19 1100
30-AUG-19 1400
We want to calculate the rolling average of transactions for last 180 days (excluding weekends). If it is 1st day, average will be equal to number of transactions on that day and if it is 2nd day it will be equal to (n1+n2)/2 and 3rd day then it will be equal to (n1+n2+n3)/3 and so on.
Any help will be highly appreciated.
Upvotes: 0
Views: 1060
Reputation: 3833
You may try this. First you need to filter out the weekends from the list, since in your question you want to find the record of last 180 days excluding weekends
. To get the days name
of date we use TO_CHAR
, and for making sure that it will read as language english we'll add 'NLS_DATE_LANGUAGE=English'
.
Once you have your list then you can simply filter your 180 records for calculation. For this you may have several methods like top
, row_number
, limit
etc. I am using row_number
. So final sample code will be like this.
with record ( SLNO, TXN_DATE, NO_OF_TXNS ) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY TXN_DATE DESC) AS SLNO,
TXN_DATE,
NO_OF_TXNS
FROM TABLE
WHERE TO_CHAR(TXN_DATE,'DY', 'NLS_DATE_LANGUAGE=English') NOT IN ('SAT', 'SUN')
)
select TXN_DATE,
NO_OF_TXNS,
(select avg(t.NO_OF_TXNS) from record t where t.TXN_DATE<=t1.TXN_DATE
and t.SLNO<180) as Sum
from record t1
Thanks to @WernfriedDomscheit for improvement.
Upvotes: 0
Reputation: 167972
You can use an analytic function with a RANGE
window. You can also use TXN_DATE - TRUNC( TXN_DATE, 'IW' )
to find the number of days of the week since the start of the ISO week (which always start on Monday) and means that your query is not tied to a specific language or session parameters (which each user can change within their session and change the language to TO_CHAR
does not give the expected output for days of the week).
SELECT TXN_DATE,
AVG( NO_OF_TXNS ) OVER (
ORDER BY TXN_DATE
RANGE BETWEEN 180 PRECEDING
AND 0 PRECEDING
) AS avg_no_of_txns
FROM table_name
WHERE NOT ( TXN_DATE - TRUNC( TXN_DATE, 'IW' ) BETWEEN 5 AND 7 );
If you want to restrict it to the last 180 days worth of data then you need to find the averages and then filter afterwards:
SELECT *
FROM (
SELECT TXN_DATE,
AVG( NO_OF_TXNS ) OVER (
ORDER BY TXN_DATE
RANGE BETWEEN 180 PRECEDING
AND 0 PRECEDING
) AS avg_no_of_txns
FROM table_name
WHERE NOT ( TXN_DATE - TRUNC( TXN_DATE, 'IW' ) BETWEEN 5 AND 7 )
)
WHERE TXN_DATE >= TRUNC( SYSDATE ) - INTERVAL '180' DAY(3);
Upvotes: 3
Reputation: 35900
You can use analytical function and I would avoid using row preeciding operator as it will not give exact result in case entry is missing for one or more days so it is better to use WHERE clause for fetching last 180 days.
SELECT TXN_DATE,
AVG(NO_OF_TXNS) OVER (ORDER BY TXN_DATE) AS ROLLING_AVERAGE
FROM YOUR_TABLE
WHERE TO_CHAR(TXN_DATE,'DY') NOT IN ('SAT','SUN')
AND TRUNC(TXN_DATE) >= TRUNC(SYSDATE) - 180
Cheers!!
Upvotes: 0