SQL Clone
SQLServerCentral is supported by Redgate
 
Log in  ::  Register  ::  Not logged in
 
 
 


help!!! calculate average rolling 4 last weeks


help!!! calculate average rolling 4 last weeks

Author
Message
Lidou123
Lidou123
SSC-Addicted
SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)

Group: General Forum Members
Points: 451 Visits: 380
Hi All,

I need your help.

Database: SQL SERVER 2008R2

I 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 3000
2012 2 5000
2012 3 6000
2012 4 7000
2012 5 8000
2012 6 9000
2012 7 1000
2012 8 6000

And 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
Lokesh Vij
Hall of Fame
Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)

Group: General Forum Members
Points: 3226 Visits: 1599
Here you go..

-- Creating table
CREATE TABLE year_week_value
(
year INT,
week INT,
value INT
);

-- Inserting test values
INSERT year_week_value
VALUES
(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 query
SELECT a.year,
a.week,
.25 * ( Isnull(b.value, 0) + Isnull(c.value, 0)
+ Isnull(d.value, 0) + Isnull(e.value, 0) ) AvgVal
FROM 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 question
Guidelines for answers on Performance questions

Link to my Blog Post --> www.SQLPathy.com

Follow me @Twitter


vinu512
vinu512
Hall of Fame
Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)

Group: General Forum Members
Points: 3461 Visits: 1626
Here is another way using Correlated SubQuery:


Create Table Ex1
(
YEAR int,
WEEKS int,
VALUE int
)

Insert Into Ex1
Select 2012, 1, 3000
Union ALL
Select 2012, 2, 5000
Union ALL
Select 2012, 3, 6000
Union ALL
Select 2012, 4, 7000
Union ALL
Select 2012, 5, 8000
Union ALL
Select 2012, 6, 9000
Union ALL
Select 2012, 7, 1000
Union 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 AvgValue
From CTE As a
Order By YEAR, WEEKS



Hope it helps.:-)

Vinu Vijayan

For better and faster solutions please check..."How to post data/code on a forum to get the best help" - Jeff Moden ;-)
Lidou123
Lidou123
SSC-Addicted
SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)

Group: General Forum Members
Points: 451 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) Sad.

Do U think that it is possible to optimize the script ?

Can I replace 'left join' by ' inner join ' ??

Lidou
Lidou123
Lidou123
SSC-Addicted
SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)

Group: General Forum Members
Points: 451 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 8
Une 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. Sad
Lidou123
Lidou123
SSC-Addicted
SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)SSC-Addicted (451 reputation)

Group: General Forum Members
Points: 451 Visits: 380
Hi Lokesh,


that works well with index .

Thank U !!!!!!!!!
Cadavre
Cadavre
SSCrazy Eights
SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)SSCrazy Eights (8.5K reputation)

Group: General Forum Members
Points: 8510 Visits: 8490
I guess I'd do it like this: -

SELECT year, week, value, ISNULL(AvgVal,0) AS AvgVal
FROM (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 AvgVal
FROM (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 table
CREATE TABLE year_week_value (year INT, week INT, value INT);

-- Inserting test values
INSERT year_week_value
VALUES (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 Vij
SELECT a.year, a.week, .25 * (Isnull(b.value, 0) + Isnull(c.value, 0) + Isnull(d.value, 0) + Isnull(e.value, 0)) AvgVal, A.value
FROM 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;

-- vinu512
WITH CTE
AS (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 AvgValue
FROM CTE AS a
ORDER BY year, week;

-- Cadavre
SELECT year, week, value, ISNULL(AvgVal,0) AS AvgVal
FROM (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 3000
2011 50 750.00 5000
2011 51 2000.00 6000
2011 52 3500.00 7000
2012 1 5250.00 3000
2012 2 5250.00 5000
2012 3 5250.00 6000
2012 4 5250.00 7000
2012 5 5250.00 8000
2012 6 6500.00 9000
2012 7 7500.00 1000
2012 8 6250.00 6000
---------------------------------------------------------------------------
---------------------------------------------------------------------------
vinu512
---------------------------------------------------------------------------
year week value rn AvgValue
----------- ----------- ----------- -------------------- -----------
2011 49 3000 1 0
2011 50 5000 2 0
2011 51 6000 3 0
2011 52 7000 4 0
2012 1 3000 5 5250
2012 2 5000 6 5250
2012 3 6000 7 5250
2012 4 7000 8 5250
2012 5 8000 9 5250
2012 6 9000 10 6500
2012 7 1000 11 7500
2012 8 6000 12 6250
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Cadavre
---------------------------------------------------------------------------
year week value AvgVal
----------- ----------- ----------- ---------------------------------------
2011 49 3000 0.000000000000000
2011 50 5000 3000.000000000000000
2011 51 6000 4000.000000000000000
2011 52 7000 4666.666666666666666
2012 1 3000 5250.000000000000000
2012 2 5000 5250.000000000000000
2012 3 6000 5250.000000000000000
2012 4 7000 5250.000000000000000
2012 5 8000 5250.000000000000000
2012 6 9000 6500.000000000000000
2012 7 1000 7500.000000000000000
2012 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 learn

For 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 nolock


Craig Wilkinson - Software Engineer
LinkedIn
vinu512
vinu512
Hall of Fame
Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)Hall of Fame (3.5K reputation)

Group: General Forum Members
Points: 3461 Visits: 1626
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 8
Une 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. Sad


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 Vijayan

For better and faster solutions please check..."How to post data/code on a forum to get the best help" - Jeff Moden ;-)
Lokesh Vij
Lokesh Vij
Hall of Fame
Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)

Group: General Forum Members
Points: 3226 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 question
Guidelines for answers on Performance questions

Link to my Blog Post --> www.SQLPathy.com

Follow me @Twitter


Lokesh Vij
Lokesh Vij
Hall of Fame
Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)Hall of Fame (3.2K reputation)

Group: General Forum Members
Points: 3226 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 question
Guidelines for answers on Performance questions

Link to my Blog Post --> www.SQLPathy.com

Follow me @Twitter


Go


Permissions

You can't post new topics.
You can't post topic replies.
You can't post new polls.
You can't post replies to polls.
You can't edit your own topics.
You can't delete your own topics.
You can't edit other topics.
You can't delete other topics.
You can't edit your own posts.
You can't edit other posts.
You can't delete your own posts.
You can't delete other posts.
You can't post events.
You can't edit your own events.
You can't edit other events.
You can't delete your own events.
You can't delete other events.
You can't send private messages.
You can't send emails.
You can read topics.
You can't vote in polls.
You can't upload attachments.
You can download attachments.
You can't post HTML code.
You can't edit HTML code.
You can't post IFCode.
You can't post JavaScript.
You can post emoticons.
You can't post or upload images.

Select a forum

































































































































































SQLServerCentral


Search