SQL - monthly average rather than daily average - sql

I have a table called values that contains 3 columns - Location, value, date
I want to work out the average value per month
so far I have
SELECT Location, Avg(value), date
FROM Value
GROUP BY Location, date
This returns the average values but a value is entered on a daily basis so I have an average per day rather than per month, how can I achieve a monthly average?

try this:
SELECT Location,
Avg(value),
month(date),
year(date)
FROM Value
GROUP BY Location,
month(date),
year(date)

You can use the following, if you want month only grouping:
SELECT Location, Avg(value) AvgVal, Month(date) Mnth
FROM Value
GROUP BY Location, Month(date)
You can even use GROUPING SETS, which will GROUP BY Month, year, location and then give you a total for all:
SELECT Location,
Avg(value) AvgVal,
Month(dt) Mnth,
Year(dt) Yr
FROM yourtable
GROUP BY
GROUPING SETS((Month(dt), Year(dt), Location), (Location));
See SQL Fiddle with Demo

SELECT
Location,
year(date),
month(date),
Avg(value)
FROM
Value
GROUP BY
Location,
year(date),
month(date)

Can also do it as the following if you want to combine the dates into one column with the first of the month as the day.
SELECT Location,
Avg(value),
DateFromParts(Year(date), Month(date) , 1) AS FirstOfMonthDate
FROM Value
GROUP BY Location,
DateFromParts(Year(date), Month(date) , 1)

Related

In pgAdmin for postgreSQL, I am unable to query for MAXimum rows from another query that SUMs up and sorts rows. Working with 1 table

This is the initial query that groups, sums up, and orders the busiest day of the week per month and year for a small retail store:
SELECT year, month, day_of_week, SUM(total_revenue)
FROM vip_sales
GROUP BY year, month, day_of_week
ORDER BY year, month, SUM DESC
and returns the table in attached image. And that is what I want to see INITIALLY.
Now I want to do a query on this result (image) that only shows the MAX sums of each month - essentially ONLY the rows that I circled, which is the best day (highest SUM) is each of the months of January (1) , February(2), ...
I tried the following:
SELECT year, month, day_of_week, MAX(SUM(total_revenue))
FROM vip_sales
GROUP BY year, month, day_of_week
ORDER BY year, month
But I got this error:
ERROR: aggregate function calls cannot be nested
LINE 1: SELECT year, month, day_of_week, MAX(SUM(total_revenue))
^
SQL state: 42803
Character: 38
Then I tried:
SELECT year, month, day_of_week, MAX(SUM)
FROM
(SELECT year, month, day_of_week, SUM(total_revenue)
FROM vip_sales
GROUP BY year, month, day_of_week
ORDER BY year, month, SUM DESC)
ORDER BY year, month
And I got another error with hint:
ERROR: subquery in FROM must have an alias
LINE 3: (SELECT year, month, day_of_week, SUM(total_revenue)
^
HINT: For example, FROM (SELECT ...) [AS] foo.
SQL state: 42601
Character: 51
So then I tried:
SELECT year, month, day_of_week, MAX(SUM)
FROM
(SELECT year, month, day_of_week, SUM(total_revenue)
FROM vip_sales
GROUP BY year, month, day_of_week
ORDER BY year, month, SUM DESC) AS foo
GROUP BY foo.year, foo.month, foo.day_of_week
ORDER BY foo.year, foo.month, MAX DESC
AND
SELECT foo.year, foo.month, foo.day_of_week, MAX(foo.SUM)
FROM
(SELECT year, month, day_of_week, SUM(total_revenue)
FROM vip_sales
GROUP BY year, month, day_of_week
ORDER BY year, month, SUM DESC) AS foo
GROUP BY foo.year, foo.month, foo.day_of_week
ORDER BY foo.year, foo.month, MAX DESC
But they are redundant and both return the SAME results as in the image - all days of the week in that month, and NOT the day of the week which is the day with maximum sales in that month in that year.
I googled 'nested queries' and 'sub queries" but I tried some techniques but got errors with no hints. I am not finding anything that logically explains how to do SUM and then query the MAXIMUM of the SUMs.
Any suggestions?
You can use ROW_NUMBER() to create a custom partition
SELECT year, month, day, thesum
FROM (
SELECT year, month, day, thesum,
ROW_NUMBER() OVER (PARTITION BY year, month ORDER BY thesum DESC) RN
FROM (
SELECT year, month, day_of_week, SUM(total_revenue) as thesum
FROM vip_sales
GROUP BY year, month, day_of_week
--ORDER BY year, month, SUM DESC
) x
) y
WHERE RN = 1

SQL - lag variable creation using window function

I have daily city level data with some counts. I have to aggregate this data at monthly level(1st day of each month) and then create lag variables based on last 1 week from 1st day of month.
I have used following code to create lag variables for last 1 month using (after aggregating data at monthly level ( with 1st date of month)
sum(count) over (partition by City order by month_date rows between 1 preceding and 1 preceding) as last_1_month_count
Is there a way to aggregate data at monthly level and create lag variables based on last 7,14,21,28 days using window function?
you can use this L
select
CITY
, month(Date)
, year(date)
, sum(count)
from table1
where date < Datediff(days , 7 , getdate())
group by
City
, month(Date)
, year(date)
I think you're looking for something like this. The first cte summarizes city counts to the day, week, month, year. The second summarizes the counts to the week, month, year. To group sales by weeks starting from the 1st day it uses the DAY function along with YEAR and MONTH. Since DAY returns and integer, groups of distinct weeks can be created by dividing by 7, i.e. DAY(day_dt)/7.
One way to get the prior week sales would be to join the week sales summary cte to itself where the week is offset by -1. Since the prior week might possible have 0 sales it seems safer to LEFT JOIN than to use LAG imo
with
day_sales_cte(city, day_dt, yr, mo, wk, sum_count) as (
select city, day_dt, year(day_dt), month(day_cte), day(day_dt)/7, sum([count]) sum_counts
from city_level_data
group by city, day_dt, year(day_dt), month(day_cte), day(day_dt)/7)
wk_sales_cte(city, yr, mo, wk, sum_count) as (
select city, yr, mo, wk, sum(sum_counts) sum_counts
from sales_cte
group by city, yr, mo, wk)
select ws.*, ws2.sum_sales prior_wk_sales
from wk_sales_cte ws
left join wk_sales_cte ws2 on ws.city=ws2.city
and ws.yr=ws2.yr
and ws.mo=ws2.mo
and ws.wk=ws.wk-1;

CTE Rolling 3 Mo Avg

output for all 3 queries
working on an assigment, below is the ask, she has directed us to use a CTE
Write SQL query code used to explore the database tables and write a query that retrieves finance amounts from "FactFinance" in the "AdventureWorksDW2016CTP3" database and returns those amounts, organized by month, and showing a 3-month rolling average
SELECT DateKey,
month(date) as [Month],
year(date) as [Year],
SUM ( ALL Amount) OVER (PARTITION BY Date ORDER BY Date ASC) AS Amount
FROM FactFinance
SELECT
YEAR(Date) AS Year,
MONTH(Date) AS Month,
SUM(Amount) AS Amount
FROM FactFinance
GROUP BY YEAR(Date), MONTH(Date)
ORDER BY Year, Month;
WITH CTE AS (
SELECT
DateKey AS Month,
AVG(Amount) AS AvgAmt
from FactFinance
group by DateKey
)
SELECT
Month,
AvgAmt
FROM CTE
GO
oUTPUT for last query Needing 3 month rolling average
First, you should know the right way to answer this. Assuming you have data for all three months, then:
SELECT YEAR(Date) AS Year,
MONTH(Date) AS Month,
SUM(Amount) AS Amount,
AVG(SUM(Amount)) OVER (ORDER BY MIN(DATE)
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as rolling_3month_avg
FROM FactFinance
GROUP BY YEAR(Date), MONTH(Date)
ORDER BY Year, Month;
If I were told to use a CTE for this, I might be tempted to do:
WITH unnecessary_cte as (
SELECT YEAR(Date) AS Year,
MONTH(Date) AS Month,
SUM(Amount) AS Amount,
AVG(SUM(Amount)) OVER (ORDER BY MIN(DATE)
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as rolling_3month_avg
FROM FactFinance
GROUP BY YEAR(Date), MONTH(Date)
)
SELECT *
FROM unnecessary_cte
ORDER BY YEAR, MONTH;
However, we can try to read your instructor's mind and speculate that she wants you to write something like this:
WITH ym as (
SELECT YEAR(Date) AS Year,
MONTH(Date) AS Month,
SUM(Amount) AS Amount
FROM FactFinance
GROUP BY YEAR(Date), MONTH(Date)
)
SELECT ym.*,
(SELECT AVG(Amount)
FROM ym ym2
WHERE 12 * ym2.year + ym2.month
BETWEEN 12 * ym.year + ym.month - 2 AND
12 * ym.year + ym.month
) as rolling_3month_avg
FROM ym
ORDER BY YEAR, MONTH;

Sql Min Max range With over function?

I have many users and Date time column. I would like to know the min and max values of each users for each year and each month?
name date Income Expense
Vijay 12-10-2017 10 8
Vijay 16-04-2017 25 12
year(date) as Y_year,
month(date) as M_Month,
I tried the code below but no use either
min(Income)over( PARTITION by (name, Y_year,M_Month)) as min_income_of_month,
Max(Expense)over( PARTITION by (name, Y_year,M_Month)) as Max_Expense_of__month
Is this what you want?
select name, year(date) as Y_year, month(date) as M_Month,
min(income), max(income), min(expense), max(expense)
from t
group by name, year(date), month(date)
order by name, Y_year, M_Month;
Just use min and max function on the columns you want to aggregate and group by user and the month of the date
No need to use window functions

Group by month and add year and employee

I have a simple table with every sale made in few past years. I would like to find out maximum sale per month and who made it and in which year and month.
Table has following columns:
Id, date, amount, employeeId
I group data by year(date), month(date), employeeId and use sum(amount) to find sale of each employee in each month. Then I group further by month(date) and use max on sum(amount) column to find maximum sale per month. This is easy.
After that I would like to find out when exactly (date) and who exactly (employeeId) made that particular sale.
Group data by year(date), month(date), employeeId and use sum(amount) to find sale of each employee in each month then order by sum(amount) desc. Your highest sellers will be at the top of the results.
Most databases support the ANSI standard rank() function. This may do what you want:
select s.*
from (select year(date) as yyyy, month(date) as mm, employeeid, sum(amount) as amount,
rank() over (partition by year(date), month(date)
order by sum(amount) desc
) as seqnum
from simpletable
) s
where seqnum = 1;
I think you can do this like, if I understand correctly:
select top 1 with ties year(date), month(date), employeeId
from TableName
group by year(date), month(date), employeeId
order by sum(amount) desc