- Marek Vavrovic

# Calculating Average using T-SQL

__Calculating average by week number.__

__Calculating average by month number.__

** data source :** Download data | Coronavirus in the UK

For the first couple of exercises, I will be using the covid-19 data set from the government website. My first task is to calculate the mean by week using t-sql language.

Example 1

*Calculating average by week number.*

*Calculating average by week number.*

For this calculation I am using DATEPART() function to return the week numbers. This function returns an** integer** that represents the specified *datepart* of the specified date. There is one more similar function to this one, DATENAME() which returns a **string **and string can not be sorted.

Select

YEAR(DATE) YEARS,

DATEPART(WW,Date) WEEKS,

AVG(NewCases) MeanByWeek from Covid_UK

Group by

YEAR(DATE),

DATEPART(WW,Date)

order by YEARS desc, WEEKS desc

Example 3

**Calculating average by month number.**

A similar calculation as in the previous case, the only thing I needed to change is the **interval** in DATEPART(**MM**, Date) function.

Example 4

*Using AVG() OVER()*

*Using AVG() OVER()*

Let's say I want to see both calculations as a part of one result. I want to create a table that includes new cases by date, average by week number, and average by month number. To achieve this, I will be using AVG() OVER() function, which is a part of the window functions.

When you specify a column or set of columns with the **PARTITION BY** clause, then it will divide the result set into record partitions. Then, finally **AVG()** function is applied to each record partition separately.

Select

date,

YEAR(DATE) YEARS,

DATEPART(MM,Date) MONTHS,

DATEPART(WW,Date) WEEKS,

NewCases,

AVG(NewCases) OVER(PARTITION BY YEAR(DATE) , DATEPART(WW,Date)

Order by YEAR(DATE),DATEPART(WW,Date) ) as MeanByWeek,

AVG(NewCases) OVER(PARTITION BY YEAR(DATE) , DATEPART(MM,Date)

Order by YEAR(DATE),DATEPART(MM,Date) ) as MeanByMonth

from Covid_UK

order by date desc

If you plot this, you can see that the new cases are slightly increasing in the last two months.

Example 5

*Moving average in T-SQL*

*Moving average in T-SQL*

There are two moving averages used with technical analysis in the Financial Markets - Simple and Exponential. The goal here is to provide you with a solution that will allow you to do Simple Moving Averages (SMA) efficiently. The moving average shows a smoother curve than the actual values, and it is a good tool for trend analysis.

Select

Date,

NewCases,

AVG(NewCases)

Over(Order by Date Rows 19 Preceding) AS MA20

From Covid_UK

**Rows 19 preceding** means start at the current row and include next 19 rows. Hence 1 current row + 19 preceding rows =20

The figures are displayed as integer. If you want to use decimals, you have to cast NewCases values.

The code bellow is displaying new cases, 20-day moving average and 60-day moving average.

Moving averages are applied as a tool to demonstrate trends. A popular approach is to combine moving averages of different intervals, to spot variations in the short-, medium- and long-term trends respectively. Of particular interest are the crossing of trend lines. For instance, when the short trend moves over the long or medium trend, this can be interpreted as a buy signal in technical analysis. And when the short trend moves under a longer trend line, this can be interpreted as a sell signal.

Select

Date,

NewCases,

AVG(NewCases)

Over(Order by Date Rows 19 preceding) AS MA20,

AVG(NewCases)

Over(Order by Date Rows 59 preceding) AS MA60

From Covid_UK

Example 6

*Weighted Moving Average *

*Weighted Moving Average*

*sample stock data *

Weighted moving average calculation = **(Price * weighting factor) + (Price previous period * weighting factor-1)** WMAs can have different weights assigned based on the number of periods used in the calculation.

In the example I will calculate weighted moving average for 9 days (WMA9). The weight for each row will be calculated by using the window row position relative to the current row. Let’s say I want to calculate WMA for the 9th row.

multiply Index * close_price

The sum of the above is The sum of the above is 24381,95. This is then divided by the sum of the weights, that is

**1+2+3+4+5+6+7+8+9 = 45**. The WMA9 for row 9 is 24381,95 /**45**= 541,8211

WITH Prices AS

(

SELECT

quote_date,

ROW_NUMBER() Over(Order by quote_date) as QouteIndex

,close_price

FROM MavaStock

)

SELECT

P.quote_date

,P.QouteIndex

,P.close_price

,CASE WHEN P.QouteIndex >= 9 THEN SUM((WMA9.QouteIndex - p.QouteIndex + 9.0) * WMA9.close_price) / 45.0 END AS WMA9

FROM

Prices AS P

LEFT OUTER JOIN

Prices AS WMA9

on

WMA9.QouteIndex <= p.QouteIndex AND WMA9.QouteIndex >= p.QouteIndex - 9

GROUP BY p.QouteIndex , P.quote_date , P.close_price

Calculating **30-day weighted moving average** for covid-19 new cases in the UK.

In case you have more countries in the table use this syntax after specifying *LEFT JOIN*

*ON** uk.Country = cuk.Country AND cuk._Index <= uk._Index AND cuk._Index >= uk._Index - 30*

With CovidUk

as

(

Select ROW_NUMBER() over(order by date) as _Index,

AreaName, Date, NewCases from Covid_UK

)

Select

uk._Index,

uk.AreaName,

uk.Date,

uk.NewCases,

CASE WHEN uk._Index >= **30** THEN SUM((cuk._Index - uk._Index + **30**) * cuk.NewCases) /** 465 **END AS WMA30

from CovidUk uk

LEFT JOIN CovidUk cuk

ON cuk._Index <= uk._Index AND cuk._Index >= uk._Index - **30**

GROUP BY uk._Index,uk.AreaName,uk.Date,uk.NewCases

Example 6

*Smoothed Moving Average*

*Smoothed Moving Average*

To clarify the long term trend, a technique called **smoothing **can be used where groups of values are averaged. The graph of moving mean or moving medians is "flatter" than the time series graph with its peaks and troughs. The average can be either a **moving mean** or a **moving median**. In this process the mean or median of groups of values are taken.

This simple example created in MS Excel demonstrates how the 3-mean smoothing works.

How to achieve this with t-sql?

By using a window function AVG() OVER()

with: ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING

*Calculating 3-Mean Smoothed using t-sql*

Select SalesYear,

Sales,

COUNT(Sales) over(order by salesYear ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS [GroupsBy3],

AVG(Sales)over(order by salesYear ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS [3-Mean Smoothed]

from SmoothingData

*Calculating 5-Mean Smoothed using t-sql*

With Sales

AS

(

Select

ROW_NUMBER() OVER(ORDER BY SalesYear) as _Index,

SalesYear,

Sales,

AVG(Cast(Sales as float))over(order by SalesYear

ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS [5-Mean Smoothed]

From SmoothingData

)

Select

SalesYear, Sales,

CASE WHEN

_Index IN (Select Top 2 _Index from Sales Order by _Index DESC)

OR

_Index IN (Select Top 2 _Index from Sales Order by _Index ASC)

THEN NULL

ELSE [5-Mean Smoothed]

END [5-Mean Smoothed]

From Sales

This is how the data appears on the visual.

*Calculating 5-Mean Smoothed using variables.*

*-variables must be declared outside the CTE*

*-SELECT TOP N is considered as a " performance killer" and variables should improve it. But this is already running in the memory, thanks to *ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING window framing so in this particular case using variables won't improve the performance. In other cases they would do so.

**Declare**** @Nr ****INT**** =2**

;With Sales

AS

(

Select

ROW_NUMBER() OVER(ORDER BY SalesYear) as _Index,

SalesYear,

Sales,

AVG(Cast(Sales as float))over(order by salesYear

ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS [5-Mean Smoothed]

From SmoothingData

)

Select

SalesYear, Sales,

CASE WHEN

_Index IN (Select Top **(****@Nr****)** _Index from Sales Order by _Index DESC)

OR

_Index IN (Select Top** ****(****@Nr****)** _Index from Sales Order by _Index ASC)

THEN NULL ELSE [5-Mean Smoothed] END [5-Mean Smoothed]

From Sales

*Both queries are performing the same way.*

I will combine smoothing averages of different intervals, to spot variations in the trends respectively for the covid-19 UK data by calculating 7 and 21 mean smoothed.

WITH UKCovidData

AS

(

Select

Date, NewCases,

ROW_NUMBER() OVER(ORDER BY Date) as** RN**,

AVG(NewCases) OVER(ORDER BY Date

ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING) AS [7-MeanSmoothed],

AVG(NewCases) OVER(ORDER BY Date

ROWS BETWEEN 10 PRECEDING AND 10 FOLLOWING) AS [21-MeanSmoothed]

From Covid_UK

)

Select Date, NewCases,

CASE WHEN

RN IN (Select Top 3 **RN **from UKCovidData Order by RN DESC)

OR

RN IN (Select Top 3 **RN** from UKCovidData Order by RN ASC)

THEN NULL ELSE [7-MeanSmoothed] END [7-Mean Smoothed],

CASE WHEN

RN IN (Select Top 10 **RN** from UKCovidData Order by RN DESC)

OR

RN IN (Select Top 10 **RN** from UKCovidData Order by RN ASC)

THEN NULL ELSE [21-MeanSmoothed] END [21-Mean Smoothed]

From UKCovidData

Order by Date desc

As you can see from this visual, new cases are slightly increasing. And because there is a strong positive correlation between new cases and hospital cases or between new cases and deaths, the hospital cases and deaths will be slightly increasing as well. If you compare the same period with the previous year, you will find out that there is a double difference in the number of new cases. The most difficult period will come in early January.