SQL: Group by specific time instead of year - sql

I have the following query:
SELECT DATEPART(yyyy, ap.Date) AS 'Year', COUNT(p.Name2) AS 'Times entered', p.Name2 AS 'Name'
FROM Person p JOIN Price ap ON ap.PersonId = p.ID
GROUP BY p.Name2, DATEPART(yyyy, ap.Date)
ORDER BY DATEPART(yyyy, ap.Date) DESC , p.Name2 ASC
As result I have the following Data:
2018 50 Bob
2018 40 Fred
2017 10 Bob
2017 5 Fred
What I actually want is to not group by year, but to group by the period of between july 2017 and june 2018.
I want to group by period of July 2017 to June 2018.
How are we possible to set a timeframe as a group by function in SQL?

Something like this should work:
SELECT g.my AS 'Month-Year',
COUNT(p.Name2) AS 'Times entered',
p.Name2 AS 'Name'
FROM Person p
JOIN Price ap ON ap.PersonId = p.ID
CROSS APPLY
(
SELECT CONCAT(DATEPART(mm, ap.Date), '-', DATEPART(yyyy, ap.Date)) AS my
) AS g
WHERE ap.Date BETWEEN '2017-07-01' AND '2018-06-30'
GROUP BY p.Name2, g.my
ORDER BY g.my DESC , p.Name2 ASC

Related

Count active users if they have made a buy in the last three months (Historical) SQL

This is my query
with months (Date,Familia) as (
select cast(eomonth(datefromparts(year(date_var),
month(date_var),01)) as datetime) as Fecha, p.family as 'Familia'
from sales v
left join products p on p.id_product=v.id_product
where date_var >= '2016-08-01'
group by date_var, p.family
)
select m.Date, m.Family, (
select count(distinct v.user_id)
from sales v
where datediff(month, m.Date, v.date_var) between -2 and 0 and
v.date_var >= '2016-08-01'
) as 'Active Users'
from months m
group by m.family, m.Date
order by m.Date
I want to obtain the number of active users, taking into account that a user counts as active if they have made a purchase in the last three months.
For instance
family
year
month
#
Nubrenza
2017
1
2500
Keppra
2017
1
350
Nubrenza
2017
2
2400
Keppra
2017
2
357
Active users of January 2017 would be count( DISTINCT users) who have made a transaction in January 2017, Dec 2016 and / or Nov 2016 and so on...
Update my query is now showing the distinct count of users grouping them by month but it's returning the same value for all my families, how can I fix that?
You can generate the months and use a subquery:
with months as (
select convert(date, '2017-01-01') as month
union all
select dateadd(month, 1, month)
from months
where month < '2018-01-01'
)
select m.month,
(select count(*)
from mytable t
where datediff(month, date_var, m.month) between 0 and 2
)
from months m;

Return a single set of results from two SQL tables

I have two SQL queries that both return the same columns.
The returned column names are month_name, month_number and total.
How can I return a single set of results from the two tables, summing the "total" field?
Query 1
SELECT DISTINCT
DATENAME(MONTH,DATEADD(MONTH,month([date]),-1 )) as month_name,
MONTH([date]) as month_number,
SUM(pur.total_expenses - pur.vat) as 'total'
FROM (select distinct ID, MONTH([date]) as month_number, DATENAME(MONTH,DATEADD(MONTH,month([date]),-1 )) as month_name from [dbo].[purchase_invoices] WHERE YEAR([date]) = '2020' ) m
LEFT JOIN [dbo].[purchase_invoices] pur ON pur.id = m.id
LEFT JOIN [dbo].[dividends] div on month(dividend_date) = month([date]) AND month(dividend_date) = '2020'
WHERE YEAR([date]) = '2020'
GROUP BY m.month_number, MONTH([date]), m.month_name
ORDER BY month_number
Query 2
SELECT DISTINCT
DATENAME(MONTH,DATEADD(MONTH,month([dividend_date]),-1 )) as month_name,
MONTH([dividend_date]) as month_number,
SUM(div.dividend_value) as 'total'
FROM (select distinct ID, MONTH([dividend_date]) as month_number, DATENAME(MONTH,DATEADD(MONTH,month([dividend_date]),-1 )) as month_name from [dbo].[dividends] WHERE YEAR([dividend_date]) = '2020' ) m
LEFT JOIN [dbo].[dividends] div ON div.id = m.id
WHERE YEAR([dividend_date]) = '2020'
GROUP BY m.month_number, MONTH([dividend_date]), m.month_name
ORDER BY month_number
I know I need a JOIN on the month_name or number field, but I am not sure on how to achieve that.
Any help greatly appreciated.
UPDATE (Expected Output)
|---------------------|------------------|------------------|
| month_name | month_number | total |
|---------------------|------------------|------------------|
| Jan | 1 | 4500 |
|---------------------|------------------|------------------|
| Feb | 2 | 6000 |
|---------------------|------------------|------------------|
| ... | ... | ... |
Try using CTEs:
WITH invoice AS (
SELECT DISTINCT
ID,
MONTH([date]) AS month_number,
DATENAME(MONTH, DATEADD(MONTH, MONTH([date]), -1)) AS month_name
FROM[dbo].[purchase_invoices]
WHERE
YEAR([date]) = '2020'
),
q1 AS (
SELECT DISTINCT
DATENAME(MONTH, DATEADD(MONTH, MONTH([date]), -1)) AS month_name,
MONTH([date]) AS month_number,
SUM(pur.total_expenses - pur.vat) AS 'total'
FROM invoice as m
LEFT JOIN[dbo].[purchase_invoices] pur
ON pur.id = m.id
LEFT JOIN[dbo].[dividends] DIV
ON MONTH(dividend_date) = MONTH([date])
AND MONTH(dividend_date) = '2020'
WHERE
YEAR([date]) = '2020'
GROUP BY
m.month_number,
MONTH([date]),
m.month_name
ORDER BY
month_number
),
dividend AS (
SELECT DISTINCT
ID,
MONTH([dividend_date]) AS month_number,
DATENAME(MONTH, DATEADD(MONTH, MONTH([dividend_date]), -1)) AS month_name
FROM[dbo].[dividends]
WHERE
YEAR([dividend_date]) = '2020'
),
q2 AS (
SELECT DISTINCT
DATENAME(MONTH, DATEADD(MONTH, MONTH([dividend_date]), -1)) AS month_name,
MONTH([dividend_date]) AS month_number,
SUM(DIV.dividend_value) AS 'total'
FROM dividend as m
LEFT JOIN[dbo].[dividends] DIV
ON DIV.id = m.id
WHERE
YEAR([dividend_date]) = '2020'
GROUP BY
m.month_number,
MONTH([dividend_date]),
m.month_name
ORDER BY
month_number
)
SELECT
month_name,
month_number,
q1.total + q2.total AS total
FROM q1
LEFT JOIN q2
ON q1.month_name = q2.month_name
AND q1.month_number = q2.month_number
You can use union all:
select month_name, month_number, sum(total)
from ((<query1 here>) union all
(<query2 here>)
) q
group by month_name, month_number;

SQL: add missing months from different years

SQL SERVER
[CreatedOn] - DATETIME
I get this table:
Year Month Count
2009 7 1
2009 9 1
2010 1 2
2010 3 13
From query:
SELECT
YEAR ([CreatedOn]) AS 'Year',
MONTH ([CreatedOn]) AS 'Month',
COUNT ([CreatedOn]) AS 'Count'
FROM xxx
GROUP BY YEAR ([CreatedOn]), MONTH ([CreatedOn])
How can I get table like this (with missed months and Count 0):
Year Month Count
2009 7 1
2009 8 0
2009 9 1
2009 10 0
2009 11 0
2009 12 0
2010 1 2
2010 2 0
2010 3 13
Syntax says you are using MSSQL. Use Recursive CTE to generate the calender table then do a Left outer join with XXX table
DECLARE #maxdate DATE = (SELECT Max([CreatedOn])
FROM xxx);
WITH calender
AS (SELECT Min([CreatedOn]) dates,
FROM xxx
UNION ALL
SELECT Dateadd(mm, 1, dates)
FROM cte
WHERE dates < #maxdate)
SELECT Year(dates) [YEAR],
Month(dates) [month],
Count ([CreatedOn]) AS 'Count'
FROM calender a
LEFT OUTER JOIN xxx b
ON Year(dates) = Year ([CreatedOn])
AND Month(dates) = Month ([CreatedOn])
GROUP BY Year(dates),
Month(dates)
Note : Instead of Recursive CTE create a physical calender table
This will use a build in table to create the calendar:
;WITH limits as
(
SELECT min([CreatedOn]) mi, max([CreatedOn]) ma
FROM xxx
), months as(
SELECT
dateadd(mm, number, mi) m
FROM
master..spt_values v
JOIN
limits l
ON
number between 0 and datediff(mm, l.mi, l.ma)
WHERE
v.type = 'P'
)
SELECT
year(months.m) year,
month(months.m) month,
count(qry.[CreatedOn]) cnt
FROM
xxx qry
RIGHT JOIN
months
ON
months.m = dateadd(mm, datediff(mm, 0, qry.[CreatedOn]), 0)
GROUP BY
year(months.m),
month(months.m)

sql server calculate cumulative number per month for different year

I have a table with "date" column. Each row represents a survey.
date
11/19/2013 5:51:41 PM
11/22/2013 1:30:38 PM
11/23/2013 3:09:17 PM
12/2/2014 5:24:17 PM
12/25/2014 11:42:56 AM
1/6/2014 2:24:49 PM
I want to count the number of survey per month cumulatively. As you see from the above table, there are 3 surveys for Nov 2013, 2 surveys for Dec 2013, 1 survey for Jan 2014. The cumulative number of survey per month would be:
month | year | number_of_survey
11 | 2013 | 3
12 | 2013 | 5
1 | 2014 | 6
I have this query which shows correct number of surveys for 2013, and number of survey for 2014 is not cumulative.
with SurveyPerMonth as -- no of Survey per month
(
select datepart(month, s.date) as month,
datepart(year, s.date) as year,
count(*) as no_of_surveys
from myTable s
group by datepart(year, s.date), datepart(month, s.date)
)
select p1.month, p1.year, sum(p2.no_of_surveys) as surveys -- cumulatively
from SurveyPerMonth p1
inner join SurveyPerMonth p2 on p1.month >= p2.month and p1.year>=p2.year **-- the problem is probably comes from this line of code**
group by p1.month, p1.year
order by p1.year, p1.month;
This query returns:
month | year | surveys
11 | 2013 | 3
12 | 2013 | 5
1 | 2014 | 1 // 2014 is not cumulative
How can I calculate cumulative number of surveys per month for 2014 as well?
Something like this ?
SELECT date = create_date INTO #myTable FROM master.sys.objects
;WITH perMonth ( [year], [month], [no_of_surveys])
AS (SELECT DatePart(year, s.date) ,
DatePart(month, s.date),
COUNT(*)
FROM #myTable s
GROUP BY datepart(year, s.date),
datepart(month, s.date))
SELECT [year],
[month],
[no_of_surveys] = ( SELECT SUM([no_of_surveys])
FROM perMonth agg
WHERE (agg.[year] < pm.[year])
OR (agg.[year] = pm.[year] AND agg.[month] <= pm.[month]))
FROM perMonth pm
ORDER BY [year], [month]
Edit: seems I missed the ball with < and >, fixed it and added small example
'--This should work.I have added a new column 'monthyear'
with surveypermonth as -- no of survey per month
(
select datepart(month, s.date) as month,
datepart(year, s.date) as year,
datepart(year, s.date) *100 + datepart(month, s.date) as monthyear,
count(*) as no_of_surveys
from test s
group by datepart(year, s.date), datepart(month, s.date),datepart(year, s.date)*100 + datepart(month, s.date)
)
select a.month,substring(cast(monthyear as varchar(6)),1,4) as year,surveys from
(
select p1.month, p1.monthyear as monthyear, sum(p2.no_of_surveys) as surveys
from surveypermonth p1
inner join surveypermonth p2 on p1.monthyear>=p2.monthyear
group by p1.month, p1.monthyear
--order by p1.monthyear, p1.month
)a

SQL Server : calculate monthly total sales incl empty months

I'm trying to calculate the total sales of a product in a month, but I would like it to include any "empty" months (with no sales) and only select the latest 12 months.
This is my code so far.
declare
#ProductNo int
set #ProductNo = 1234
SELECT
YEAR(o.OrderDate) as 'Year', MONTH(o.OrderDate) as 'Month', sum(Amount) as 'Units sold',[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
Group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
Order by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
This returns
Year Month Units sold
2011 6 2
2011 10 1
2011 11 1
2012 2 1
But I would like it to return.
Year Month Units sold
2011 4 0
2011 5 0
2011 6 2
2011 7 0
2011 8 0
2011 9 0
2011 10 1
2011 11 1
2011 12 0
2012 1 0
2012 2 2
2012 3 0
I'm using SQL Server 2008 R2 Sp1
I've done before I know that you have calendar table. I've used master.dbo.spt_values to generate last twelve consecutive months (including current).
declare #ProductNo int
set #ProductNo = 1234
select MONTH(d.date), YEAR(d.date), isnull(t.amnt, 0) as [Units sold] from (
SELECT
YEAR(o.OrderDate) as 'Year',
MONTH(o.OrderDate) as 'Month',
sum(Amount) as amnt,
[ProductNo]
FROM [OrderLine] ol
inner join [Order] o on ol.OrderNo = o.OrderNo
where ProductNo = #ProductNo
group by ProductNo, YEAR(o.OrderDate), Month(o.OrderDate)
) t
right join (
select dateadd(mm, -number, getdate()) as date
from master.dbo.spt_values
where type = 'p' and number < 12
) d on year(d.date) = t.[year] and month(d.date) = t.[month]
order by YEAR(d.date), MONTH(d.date)
Try:
;with CTE as
(select 0 months_ago union all
select months_ago - 1 months_ago from CTE where months_ago > -11),
month_list as
(select dateadd(MONTH,
months_ago,
dateadd(DAY,
1-datepart(DAY,getdate()),
cast(GETDATE() as DATE))) month_start
from cte)
SELECT YEAR(ml.start_date) as 'Year',
MONTH(ml.start_date) as 'Month',
sum(Amount) as 'Units sold',[ProductNo]
FROM month_list ml
left join [Order] o
on o.OrderDate >= ml.start_date and
o.OrderDate < dateadd(MONTH, 1, ml.start_date)
left join [OrderLine] ol
on ol.OrderNo = o.OrderNo and ProductNo = #ProductNo
Group by ProductNo, YEAR(ml.start_date), Month(ml.start_date)
Order by ProductNo, YEAR(ml.start_date), Month(ml.start_date)