Group by month and add year and employee - sql

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

Related

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;

How to sort by month name

I have such query:
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY MonthName(Month(Transaction_Date))
ORDER BY MonthName(Month(Transaction_Date))
But results aren't sorted by date. How to sort the by month name: January, February, March etc?
One method is to include both in the GROUP BY:
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY MonthName(Month(Transaction_Date)), Month(Transaction_Date)
ORDER BY Month(Transaction_Date);
Or just aggregate by MONTH():
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY Month(Transaction_Date)
ORDER BY Month(Transaction_Date);
The MONTHNAME() is then applied after the aggregations.
Alternatively, if the Transaction_Dates are all from the same year, use aggregation functions:
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY MonthName(Month(Transaction_Date))
ORDER BY MIN(Transaction_Date);
Note that you may also want to be including the year along with the month -- that is a best practice, because usually you don't want to mix data from different years in the same month.
Order the results by the month number as opposed to the month name, e.g.:
SELECT MonthName(Month(Transaction_Date)), Sum(Sales)
FROM Sales
GROUP BY MonthName(Month(Transaction_Date)), Month(Transaction_Date)
ORDER BY Month(Transaction_Date)
Ordering by the month name would be alphabetical but if you just order by Month(transaction_date) ASC/DESC that should order your results correctly.
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY Month(Transaction_Date)
ORDER BY Month(Transaction_Date)
I guess you should order by transaction date.
SELECT
MonthName(Month(Transaction_Date))
As Month_Name , SUM(Sales)
FROM Sales
GROUP BY Month_Name
ORDER BY Transaction_Date
Try using this query:
SELECT MonthName(Month(Transaction_Date)), SUM(Sales)
FROM Sales
GROUP BY MonthName(Month(Transaction_Date))
ORDER BY Transaction_Date ASC
Note that :
ASC - for ascending A to Z order
DESC - for descending Z to A order

Find max value for each year

I have a question that is asking:
-List the max sales for each year?
I think I have the starter query but I can't figure out how to get all the years in my answer:
SELECT TO_CHAR(stockdate,'YYYY') AS year, sales
FROM sample_newbooks
WHERE sales = (SELECT MAX(sales) FROM sample_newbooks);
This query gives me the year with the max sales. I need max sales for EACH year. Thanks for your help!
Use group by and max if all you need is year and max sales of the year.
select
to_char(stockdate, 'yyyy') year,
max(sales) sales
from sample_newbooks
group by to_char(stockdate, 'yyyy')
If you need rows with all the columns with max sales for the year, you can use window function row_number:
select
*
from (
select
t.*,
row_number() over (partition by to_char(stockdate, 'yyyy') order by sales desc) rn
from sample_newbooks t
) t where rn = 1;
If you want to get the rows with ties on sales, use rank:
select
*
from (
select
t.*,
rank() over (partition by to_char(stockdate, 'yyyy') order by sales desc) rn
from sample_newbooks t
) t where rn = 1;

SQL: aggregation (group by like) in a column

I have a select that group by customers spending of the past two months by customer id and date. What I need to do is to associate for each row the total amount spent by that customer in the whole first week of the two month time period (of course it would be a repetition for each row of one customer, but for some reason that's ok ). do you know how to do that without using a sub query as a column?
I was thinking using some combination of OVER PARTITION, but could not figure out how...
Thanks a lot in advance.
Raffaele
Query:
select customer_id, date, sum(sales)
from transaction_table
group by customer_id, date
If it's a specific first week (e.g. you always want the first week of the year, and your data set normally includes January and February spending), you could use sum(case...):
select distinct customer_id, date, sum(sales) over (partition by customer_ID, date)
, sum(case when date between '1/1/15' and '1/7/15' then Sales end)
over (partition by customer_id) as FirstWeekSales
from transaction_table
In response to the comments below; I'm not sure if this is what you're looking for, since it involves a subquery, but here's my best shot:
select distinct a.customer_id, date
, sum(sales) over (partition by a.customer_ID, date)
, sum(case when date between mindate and dateadd(DD, 7, mindate)
then Sales end)
over (partition by a.customer_id) as FirstWeekSales
from transaction_table a
left join
(select customer_ID, min(date) as mindate
from transaction_table group by customer_ID) b
on a.customer_ID = b.customer_ID

SQL - monthly average rather than daily average

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)