## help!!! calculate average rolling 4 last weeks

 Author Message Lidou123 SSC-Enthusiastic Group: General Forum Members Points: 141 Visits: 380 Hi All,I need your help.Database: SQL SERVER 2008R2I want to calculte for a year and a week the average of value of the 4 last weeks.I have data a table like that:YEAR WEEKS VALUE 2012 1 30002012 2 50002012 3 60002012 4 70002012 5 80002012 6 90002012 7 10002012 8 6000And I want that :YEAR WEEKS VALUE 2012 1 ( Average value for week 49, 50, 51, 52 for the year 2011)2012 2 ( Average value for week 50, 51, 52 for the year 2011 and week 1 for the year 2012)2012 3 ( Average value for week 51, 52 for the year 2011 and week 1, 2 for the year 2012)2012 4 ( Average value for week 52 for the year 2011 and week 1, 2, 3 for the year 2012)2012 5 5250 -> ( Average value for week 1, 2, 3 , 4 for the year 2012)2012 6 6500 -> ( Average value for week 2, 3 , 4, 5 for the year 2012)Thank U for your help Lokesh Vij SSCrazy Group: General Forum Members Points: 2076 Visits: 1599 Here you go..`-- Creating tableCREATE TABLE year_week_value ( year INT, week INT, value INT ); -- Inserting test valuesINSERT year_week_valueVALUES (2011,49,3000),(2011,50,5000),(2011,51,6000),(2011,52,7000),(2012,1,3000),(2012,2,5000),(2012,3,6000),(2012,4,7000),(2012,5,8000),(2012,6,9000),(2012,7,1000),(2012,8,6000);-- Resultant querySELECT a.year, a.week, .25 * ( Isnull(b.value, 0) + Isnull(c.value, 0) + Isnull(d.value, 0) + Isnull(e.value, 0) ) AvgValFROM year_week_value a LEFT JOIN year_week_value b ON b.year = Year(Dateadd(wk, a.week - 2, Dateadd(year, a.year - 1900, 0))) AND b.week = Datepart(wk, Dateadd(wk, a.week - 2, 0)) LEFT JOIN year_week_value c ON c.year = Year(Dateadd(wk, a.week - 3, Dateadd(year, a.year - 1900, 0))) AND c.week = Datepart(wk, Dateadd(wk, a.week - 3, 0)) LEFT JOIN year_week_value d ON d.year = Year(Dateadd(wk, a.week - 4, Dateadd(year, a.year - 1900, 0))) AND d.week = Datepart(wk, Dateadd(wk, a.week - 4, 0)) LEFT JOIN year_week_value e ON e.year = Year(Dateadd(wk, a.week - 5, Dateadd(year, a.year - 1900, 0))) AND e.week = Datepart(wk, Dateadd(wk, a.week - 5, 0))ORDER BY a.year, a.week` ~ Lokesh Vij Guidelines for quicker answers on T-SQL questionGuidelines for answers on Performance questionsLink to my Blog Post --> www.SQLPathy.comFollow me @Twitter vinu512 SSCommitted Group: General Forum Members Points: 1693 Visits: 1625 Here is another way using Correlated SubQuery: `Create Table Ex1 ( YEAR int, WEEKS int, VALUE int ) Insert Into Ex1 Select 2012, 1, 3000Union ALL Select 2012, 2, 5000Union ALL Select 2012, 3, 6000Union ALL Select 2012, 4, 7000Union ALL Select 2012, 5, 8000Union ALL Select 2012, 6, 9000Union ALL Select 2012, 7, 1000Union ALL Select 2012, 8, 6000 ;With CTE As ( Select *, ROW_NUMBER() Over(Order By Year, Weeks) As rn From Ex1 )Select *, (Case When (Select Count(*) From CTE Where rn < a.rn) >= 4 Then (Select AVG(VALUE) From CTE As b Where b.rn IN(Select Top 4 rn From CTE Where rn < a.rn Order By rn DESC)) Else '' End) As AvgValueFrom CTE As aOrder By YEAR, WEEKS ` Hope it helps.:-) Vinu VijayanFor better and faster solutions please check..."How to post data/code on a forum to get the best help" - Jeff Moden ;-) Lidou123 SSC-Enthusiastic Group: General Forum Members Points: 141 Visits: 380 Hi Lokesh,Thank You for your answer.I tested the script but the execution is too long ( about 30 minutes for 1064 lines) .Do U think that it is possible to optimize the script ? Can I replace 'left join' by ' inner join ' ??Lidou Lidou123 SSC-Enthusiastic Group: General Forum Members Points: 141 Visits: 380 Hi Vinu,thank U for your answer !!!I tested the script but I have an error !!! it is in french .Msg 116, Niveau 16, État 1, Ligne 8Une seule expression peut être spécifiée dans la liste de sélection quand la sous-requête n'est pas introduite par EXISTS.So I can Use only one expression in a sub request. Lidou123 SSC-Enthusiastic Group: General Forum Members Points: 141 Visits: 380 Hi Lokesh,that works well with index .Thank U !!!!!!!!! Cadavre Hall of Fame Group: General Forum Members Points: 3924 Visits: 8472 I guess I'd do it like this: -`SELECT year, week, value, ISNULL(AvgVal,0) AS AvgValFROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) a(year,week,value,pos)OUTER APPLY (SELECT SUM(b.value)/(COUNT(1)*1.00) FROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) b(year,week,value,pos) WHERE a.pos >= b.pos AND a.pos-4 <= b.pos) ab(AvgVal);``SELECT year, week, value, ISNULL(AvgVal,0) AS AvgValFROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) a(year,week,value,pos)OUTER APPLY (SELECT SUM(b.value)/(COUNT(1)*1.00) FROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) b(year,week,value,pos) WHERE a.pos > b.pos AND a.pos-5 < b.pos) ab(AvgVal);`However, all three of the solutions so far give different results so we may have all misunderstood your requirements.So, let's look at some sample data: -`-- Creating tableCREATE TABLE year_week_value (year INT, week INT, value INT);-- Inserting test valuesINSERT year_week_valueVALUES (2011, 49, 3000), (2011, 50, 5000), (2011, 51, 6000), (2011, 52, 7000), (2012, 1, 3000), (2012, 2, 5000), (2012, 3, 6000), (2012, 4, 7000), (2012, 5, 8000), (2012, 6, 9000), (2012, 7, 1000), (2012, 8, 6000);`Now the three solutions: -`-- Lokesh VijSELECT a.year, a.week, .25 * (Isnull(b.value, 0) + Isnull(c.value, 0) + Isnull(d.value, 0) + Isnull(e.value, 0)) AvgVal, A.valueFROM year_week_value aLEFT JOIN year_week_value b ON b.year = Year(Dateadd(wk, a.week - 2, Dateadd(year, a.year - 1900, 0))) AND b.week = Datepart(wk, Dateadd(wk, a.week - 2, 0))LEFT JOIN year_week_value c ON c.year = Year(Dateadd(wk, a.week - 3, Dateadd(year, a.year - 1900, 0))) AND c.week = Datepart(wk, Dateadd(wk, a.week - 3, 0))LEFT JOIN year_week_value d ON d.year = Year(Dateadd(wk, a.week - 4, Dateadd(year, a.year - 1900, 0))) AND d.week = Datepart(wk, Dateadd(wk, a.week - 4, 0))LEFT JOIN year_week_value e ON e.year = Year(Dateadd(wk, a.week - 5, Dateadd(year, a.year - 1900, 0))) AND e.week = Datepart(wk, Dateadd(wk, a.week - 5, 0))ORDER BY a.year, a.week;-- vinu512WITH CTEAS (SELECT *, ROW_NUMBER() OVER (ORDER BY year, week) AS rn FROM year_week_value )SELECT *, (CASE WHEN (SELECT Count(*) FROM CTE WHERE rn < a.rn) >= 4 THEN (SELECT AVG(VALUE) FROM CTE AS b WHERE b.rn IN (SELECT TOP 4 rn FROM CTE WHERE rn < a.rn ORDER BY rn DESC )) ELSE '' END) AS AvgValueFROM CTE AS aORDER BY year, week; -- CadavreSELECT year, week, value, ISNULL(AvgVal,0) AS AvgValFROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) a(year,week,value,pos)OUTER APPLY (SELECT SUM(b.value)/(COUNT(1)*1.00) FROM (SELECT year, week, value, ROW_NUMBER() OVER(ORDER BY year,week) FROM year_week_value) b(year,week,value,pos) WHERE a.pos >= b.pos AND a.pos-4 <= b.pos) ab(AvgVal);`And the results: -`---------------------------------------------------------------------------Lokesh Vij---------------------------------------------------------------------------year week AvgVal value----------- ----------- --------------------------------------- -----------2011 49 0.00 30002011 50 750.00 50002011 51 2000.00 60002011 52 3500.00 70002012 1 5250.00 30002012 2 5250.00 50002012 3 5250.00 60002012 4 5250.00 70002012 5 5250.00 80002012 6 6500.00 90002012 7 7500.00 10002012 8 6250.00 6000------------------------------------------------------------------------------------------------------------------------------------------------------vinu512---------------------------------------------------------------------------year week value rn AvgValue----------- ----------- ----------- -------------------- -----------2011 49 3000 1 02011 50 5000 2 02011 51 6000 3 02011 52 7000 4 02012 1 3000 5 52502012 2 5000 6 52502012 3 6000 7 52502012 4 7000 8 52502012 5 8000 9 52502012 6 9000 10 65002012 7 1000 11 75002012 8 6000 12 6250------------------------------------------------------------------------------------------------------------------------------------------------------Cadavre---------------------------------------------------------------------------year week value AvgVal----------- ----------- ----------- ---------------------------------------2011 49 3000 0.0000000000000002011 50 5000 3000.0000000000000002011 51 6000 4000.0000000000000002011 52 7000 4666.6666666666666662012 1 3000 5250.0000000000000002012 2 5000 5250.0000000000000002012 3 6000 5250.0000000000000002012 4 7000 5250.0000000000000002012 5 8000 5250.0000000000000002012 6 9000 6500.0000000000000002012 7 1000 7500.0000000000000002012 8 6000 6250.000000000000000`So I guess my advice is to always post sample data and expected results in the future. But for this problem, you need to figure out whether any of these solutions give the results you expect. Forever trying to learnFor better, quicker answers on T-SQL questions, click on the following...http://www.sqlservercentral.com/articles/Best+Practices/61537/For better, quicker answers on SQL Server performance related questions, click on the following...http://www.sqlservercentral.com/articles/SQLServerCentral/66909/If you litter your database queries with nolock query hints, are you aware of the side effects?Try reading a few of these links...(*) Missing rows with nolock(*) Allocation order scans with nolock(*) Consistency issues with nolock(*) Transient Corruption Errors in SQL Server error log caused by nolock(*) Dirty reads, read errors, reading rows twice and missing rows with nolockCraig Wilkinson - Software EngineerLinkedIn vinu512 SSCommitted Group: General Forum Members Points: 1693 Visits: 1625 Lidou123 (12/20/2012)Hi Vinu,thank U for your answer !!!I tested the script but I have an error !!! it is in french .Msg 116, Niveau 16, État 1, Ligne 8Une seule expression peut être spécifiée dans la liste de sélection quand la sous-requête n'est pas introduite par EXISTS.So I can Use only one expression in a sub request. Hi Lidou,Are you executing the same script that I posted??.....It seems to work perfectly on my box and I think on Cadavre's box as well. Vinu VijayanFor better and faster solutions please check..."How to post data/code on a forum to get the best help" - Jeff Moden ;-) Lokesh Vij SSCrazy Group: General Forum Members Points: 2076 Visits: 1599 Lidou123 (12/20/2012)Hi Lokesh,that works well with index .Thank U !!!!!!!!!Gald that you found out a way to improve the query using an Index :-) ~ Lokesh Vij Guidelines for quicker answers on T-SQL questionGuidelines for answers on Performance questionsLink to my Blog Post --> www.SQLPathy.comFollow me @Twitter Lokesh Vij SSCrazy Group: General Forum Members Points: 2076 Visits: 1599 Cadavre (12/20/2012)So I guess my advice is to always post sample data and expected results in the future. But for this problem, you need to figure out whether any of these solutions give the results you expect.I take by your words Cadavre!OP - please take care in future. That will really help you and us both :-) ~ Lokesh Vij Guidelines for quicker answers on T-SQL questionGuidelines for answers on Performance questionsLink to my Blog Post --> www.SQLPathy.comFollow me @Twitter