Get total sales of last 12 months even if values are null - sql

I have following code in which it presently gives month wise Total Sales for current year, I need to get total sales from last month of previous year to current month of this year.
My query is as follows:
;WITH mcte AS (
SELECT DATEADD(year, -1, getdate()) as MONTH_NAME
UNION ALL
SELECT DATEADD(MONTH,1,MONTH_NAME)
FROM mcte
WHERE DATEPART(MONTH,MONTH_NAME) < 12),octe AS(
SELECT (DATENAME (MONTH, DATEADD ( MONTH, DATEPART(MONTH, OI.CreatedDate), -1) )) AS MONTH_NAME,
SUM (OI.ItemQty * OI.TotalPrice) AS TOTAL_SALES
FROM Order_Item OI
GROUP BY MONTH(OI.CreatedDate))
SELECT DATENAME(MONTH,m.MONTH_NAME) + '' + DATENAME(YEAR,m.MONTH_NAME) as
MONTH_NAME, o.TOTAL_SALES FROM mcte m LEFT JOIN octe o ON o.MONTH_NAME = DATENAME(MONTH,m.MONTH_NAME)
and I am getting records
MONTH_NAME TOTAL_SALES
July2019 54023.45
August2019 NULL
December2019 NULL
September2019 NULL
October2019 NULL
November2019 NULL
Here I am only getting data for previous year only, not getting data for current year.Can anyone please guide me on this.
Thank you

You are only generating months up to 12. Try replacing the first CTE with:
WITH mcte AS (
SELECT DATEADD(year, -1, getdate()) as MONTH_NAME
UNION ALL
SELECT DATEADD(MONTH,1,MONTH_NAME)
FROM mcte
WHERE month_name < GETDATE()
),
Note the difference is the WHERE clause.
The entire query should look like this:
WITH months AS (
SELECT DATEFROMPARTS(YEAR(getdate()) - 1, MONTH(getdate()), 1) as month
UNION ALL
SELECT DATEADD(MONTH, 1, month)
FROM months
WHERE EOMONTH(month) < GETDATE()
)
SELECT m.month, SUM(OI.ItemQty * OI.TotalPrice) AS TOTAL_SALES
FROM months m LEFT JOIN
Order_Item OI oi
ON oi.CreatedDate >= m.month AND
oi.CreatedDate < DATEAADD(month, 1, m.month)
GROUP BY m.month

Try doing this:
DECLARE #CurDate DATE = GET_DATE()
DECLARE #OneYearPrior DATE = DATEADD(YEAR, -1, #CurDate)
WITH relevant_months(start_date, month_of_sale, year_of_sale) AS (
SELECT
#CurDate AS start_date,
MONTH(#CurDate) as month_of_sale,
YEAR(#CurDate) as year_of_sale
UNION ALL
SELECT DATEADD(MONTH, -1, start_date) AS start_date,
MONTH(DATEADD(MONTH, -1, start_date)) as month_of_sale,
YEAR(DATEADD(MONTH, -1, start_date)) AS year_of_sale
FROM relevant_months
WHERE DATEADD(MONTH, -1, start_date) >= #OneYearPrior
),
relevant_data AS (
SELECT OI.CreatedDate,
OI.ItemQty,
OI.TotalPrice,
MONTH(OI.CreatedDate), AS month_of_sale,
YEAR(OI.CreatedDate) AS year_of_sale
FROM Order_Item OI
WHERE OI.CreatedDate >= DATEADD(YEAR, -1, GETDATE())
)
SELECT rm.month_of_sale as month, rm.year_of_sale as year,
SUM(rd.ItemQty*rd.TotalPrice) as total_sales
FROM relevant_months rm
LEFT JOIN relevant_data rd
ON rm.month_of_sale = rd.month_of_sale
AND rm.year_of_sale = rd.year_of_sale
GROUP BY rm.month_of_sale, rm.year_of_sale
ORDER BY rm.year_of_sale asc, rm.month_of_sale asc

Related

Calendar Table in SQL Server

I am trying to create a Calendar Table with following columns and requirements. I have this calendar table made previously and I am not able to update it to my current requirements.
Date
Week No
Week Name
Week Start Date
Week End Date
Month
Month Start Date
Month End Date
List item
Quarter
Quarter Start Date
Quarter End Date
Year
Requirements
--Week Starts from Sunday and ends at Saturday
--Week Name should be in format 31Aug--to--06Sep
--Month should be ending date of Week's Month
--Calendar should start from 2015-08-31
--Financial Year should be in format of FY16-17
--Year should start from 1-Jun Till 31 May
--Quarter should be of 3 months of above mentioned dates
--Week No should be incremental number should not get reset after year completion.
The Query
DECLARE #StartDate date = '20150831'
DECLARE #CutoffDate date = '20300101'
;WITH seq(n) AS
(
SELECT 0 UNION ALL SELECT n + 1 FROM seq
WHERE n < DATEDIFF(DAY, #StartDate, #CutoffDate)
),
d(d) AS
(
SELECT DATEADD(DAY, n, #StartDate) FROM seq
),
src AS /*SOURCE TABLE WITH OBJECT DEFINITION*/
(
SELECT
TheDate = CONVERT(date, d),
TheDay = DATEPART(DAY, d),
TheDayName = DATENAME(WEEKDAY, d),
TheWeek = DATEPART(WEEK, d),
TheDayOfWeek = DATEPART(WEEKDAY, d),
TheMonth = DATEPART(MONTH, d),
TheMonthName = DATENAME(MONTH, d),
TheQuarter = Concat('Q',DATEPART(Quarter, d)),
Financial_Year = DATEPART(YEAR, d),
Financial_Quarter=Datepart(QUARTER,d),
TheYear = DATEPART(YEAR, d),
TheFirstOfMonth = DATEFROMPARTS(YEAR(d), MONTH(d), 1),
TheFirstOfFYear = DATEFROMPARTS(YEAR(d), 4, 1),
TheFirstOfYear = DATEFROMPARTS(YEAR(d), 1, 1),
TheLastOfYear = DATEFROMPARTS(YEAR(d), 12, 31),
TheDayOfYear = DATEPART(DAYOFYEAR, d)
FROM d
),
Dimension AS
(
SELECT
TheDate,
TheDay,
TheDayName,
TheDayOfWeek,
-- TheDayOfWeekInMonth = CONVERT(tinyint, ROW_NUMBER() OVER
-- (PARTITION BY TheFirstOfMonth, TheDayOfWeek ORDER BY TheDate)),
TheDayOfYear,
TheWeek,
TheFirstOfWeek = DATEADD(DAY, 1 - TheDayOfWeek, TheDate),
TheLastOfWeek = DATEADD(DAY, 6, DATEADD(DAY, 1 - TheDayOfWeek, TheDate)),
TheMonth,
TheMonthName,
TheFirstOfMonth,
TheLastOfMonth = MAX(TheDate) OVER (PARTITION BY TheYear, TheMonth),
TheFirstOfNextMonth = DATEADD(MONTH, 1, TheFirstOfMonth),
TheLastOfNextMonth = DATEADD(DAY, -1, DATEADD(MONTH, 2, TheFirstOfMonth)),
TheQuarter,
TheFirstOfQuarter = MIN(TheDate) OVER (PARTITION BY TheYear, TheQuarter),
TheLastOfQuarter = MAX(TheDate) OVER (PARTITION BY TheYear, TheQuarter),
TheYear,
TheFirstOfYear = DATEFROMPARTS(TheYear, 1, 1),
TheFirstOfFYear = DATEFROMPARTS(TheYear, 4, 1),
TheLastOfYear,
MMYYYY = CONVERT(char(2), CONVERT(char(8), TheDate, 101))
+ CONVERT(char(4), TheYear),
Financial_Quarter = Datepart(Quarter,DATEADD(MONTH, -3, TheFirstOfMonth)), /*Starting Financial Quarter from April*/
Financial_Year =CASE
WHEN Financial_Quarter = 1 THEN DATEPART(Year,Dateadd(Year,-1,TheFirstofYear)) ELSE THEYEAR END
FROM src
)
SELECT * FROM Dimension
ORDER BY TheDate
OPTION (MAXRECURSION 0);
How to convert Months depending on the weeks for example a month starts on Sunday (week also starts from Sunday) date be 01-MM-YYYY and the month should always end on Saturday giving 4 weeks normally in a month. The month cannot start or end with dates of previous week or month it should always have only the whole weeks, starting from Sunday and ending on Saturday.
As I mention in the comments, seems you just need a windowed COUNT. This is a guess, based on a lack of expected results, but this should get you on the right path. I also use the same set based method I used for your colleague's question:
DECLARE #StartDate date = '20150831'
DECLARE #CutoffDate date = '20300101';
/*
; is a terminator, not a "beginingator". It goes at the end of ALL your statements,
not at the start of statements that require the PREVIOUS statement to be properly terminated.
*/
WITH N AS
(SELECT N
FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS
(SELECT 0 AS I
UNION ALL
SELECT TOP (DATEDIFF(DAY, #StartDate, #CutoffDate))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1,N N2,N N3, N N4), --Up to 1000 rows. Add more cross joins for more rows
D AS
(SELECT DATEADD(DAY, T.I, #StartDate) AS d
FROM Tally T),
Src AS /*SOURCE TABLE WITH OBJECT DEFINITION*/
(SELECT CONVERT(date, d) AS TheDate,
DATEPART(DAY, d) AS TheDay,
DATENAME(WEEKDAY, d) AS TheDayName,
DATEPART(WEEK, d) AS TheWeek,
DATEPART(WEEKDAY, d) AS TheDayOfWeek,
DATEPART(MONTH, d) AS TheMonth,
DATENAME(MONTH, d) AS TheMonthName,
CONCAT('Q', DATEPART(QUARTER, d)) AS TheQuarter,
DATEPART(YEAR, d) AS Financial_Year,
DATEPART(QUARTER, d) AS Financial_Quarter,
DATEPART(YEAR, d) AS TheYear,
DATEFROMPARTS(YEAR(d), MONTH(d), 1) AS TheFirstOfMonth,
DATEFROMPARTS(YEAR(d), 4, 1) AS TheFirstOfFYear,
DATEFROMPARTS(YEAR(d), 1, 1) AS TheFirstOfYear,
DATEFROMPARTS(YEAR(d), 12, 31) AS TheLastOfYear,
DATEPART(DAYOFYEAR, d) AS TheDayOfYear
FROM d),
Dimension AS
(SELECT TheDate,
TheDay,
TheDayName,
TheDayOfWeek,
CONVERT(tinyint, ROW_NUMBER() OVER (PARTITION BY TheFirstOfMonth, TheDayOfWeek ORDER BY TheDate)) AS TheDayOfWeekInMonth,
TheDayOfYear,
TheWeek,
DATEADD(DAY, 1 - TheDayOfWeek, TheDate) AS TheFirstOfWeek,
DATEADD(DAY, 6, DATEADD(DAY, 1 - TheDayOfWeek, TheDate)) AS TheLastOfWeek,
CONVERT(tinyint, DENSE_RANK() OVER (PARTITION BY TheYear, TheMonth ORDER BY TheWeek)) AS TheWeekOfMonth,
TheMonth,
TheMonthName,
TheFirstOfMonth,
MAX(TheDate) OVER (PARTITION BY TheYear, TheMonth) AS TheLastOfMonth,
DATEADD(MONTH, 1, TheFirstOfMonth) AS TheFirstOfNextMonth,
DATEADD(DAY, -1, DATEADD(MONTH, 2, TheFirstOfMonth)) AS TheLastOfNextMonth,
TheQuarter,
MIN(TheDate) OVER (PARTITION BY TheYear, TheQuarter) AS TheFirstOfQuarter,
MAX(TheDate) OVER (PARTITION BY TheYear, TheQuarter) AS TheLastOfQuarter,
TheYear,
DATEFROMPARTS(TheYear, 1, 1) AS TheFirstOfYear,
DATEFROMPARTS(TheYear, 4, 1) AS TheFirstOfFYear,
TheLastOfYear,
CONVERT(char(2), CONVERT(char(8), TheDate, 101)) + CONVERT(char(4), TheYear) AS MMYYYY,
DATEPART(QUARTER, DATEADD(MONTH, -3, TheFirstOfMonth)) AS Financial_Quarter, /*Starting Financial Quarter from April*/
CASE
WHEN Financial_Quarter = 1 THEN DATEPART(YEAR, DATEADD(YEAR, -1, TheFirstOfYear))
ELSE TheYear
END AS Financial_Year,
COUNT(CASE WHEN DATENAME(WEEKDAY,TheDate) = 'Sunday' THEN 1 END) OVER (PARTITION BY YEAR(TheDate), MONTH(TheMonth) ORDER BY TheDate) AS TheWeekNo
FROM src)
SELECT *
FROM Dimension
ORDER BY TheDate;
Here is a single SELECT query that uses the WITH RECURSIVE statement. It does not require loops procedures etc.
A RECURSIVE SQL common table expression (CTE) is a query that continuously references a previous result until it returns an empty result. It's achieved using a CTE, which in SQL is known as a “WITH” statement.
In the query below, the second date_range with statement has a UNION ALL. The first query in that statement is the first record of the table, and the subsequent records are all from the UNION ALL second statement where it continuously references itself until it reaches the end_date, as expresses as "WHERE next_date <= end_date"
WITH RECURSIVE min_max_dates AS (
SELECT
MIN(start_at) start_date,
MAX(end_at) end_date
FROM table_or_hard_code ay
),
date_range AS (
select
start_date date,
DATE_TRUNC('month', start_date) month_date,
MONTH(start_date) as month_num,
YEAR(start_date) as month_year,
TO_CHAR((start_date),'MMMM') as month_display,
MONTHNAME (start_date) as month_short_display,
CONCAT(TO_CHAR((start_date),'MMMM'), ', ', YEAR(start_date)) as month_year_display,
DATEADD(DAY, 1, start_date) as next_date,
start_date,
end_date
FROM min_max_dates
UNION ALL
SELECT
dr.next_date date,
DATE_TRUNC('month', dr.next_date) month_date,
MONTH(dr.next_date) as month_num,
YEAR(dr.next_date) as month_year,
TO_CHAR((dr.next_date),'MMMM') as month_display,
MONTHNAME (dr.next_date) as month_short_display,
CONCAT(TO_CHAR((dr.next_date),'MMMM'), ', ', YEAR(dr.next_date)) as month_year_display,
DATEADD(DAY, 1, dr.next_date) as next_date,
start_date,
end_date
FROM date_range dr
WHERE next_date <= end_date
)
SELECT date, month_date, month_year, month_num, month_display, month_short_display, month_year_display
FROM date_range

How to use fiscal calendar in a query

I have two tables "Fiscal_calendar" and "Sales". The 2 tables do not link together. I want to be able to write a query that calculates the total sales made a in a week according to the fiscal calendar. Is this possible? Our fiscal calendar starts from December 1st and every month end falls on a friday.
Any help would be appreciated.
Fiscal_calendar
Period Period1_StartDate Period1_EndDate Period2_StartDate Period2_EndDate...........
2018 01/12/2017 29/12/2017 30/01/2018 26/01/2018
Sales
Sales_order_no Amount Date Customer
111 20453 03/12/2017 abc
112 23154 04/12/2017 bbb
113 20201 10/12/2017 ddd
114 39012 11/12/2017 ccc
115 11111 18/12/2017 eee
116 22222 25/12/2017 uuu
So there are 4 weeks between Period 1 startdate and enddate. And the first 2 sales fall under week 1. So total sales for Week 1 would be 43607
OUTPUT
WEEK Total_Sales
W1 43607
W2 59213
W3 11111
W4 22222
Two uses of CROSS APPLY to fix (normalise) the fiscal calendar table in to something useful, then a simple GROUP BY.
The WHERE clause picks the row from the fiscal calendar, that the period or week (or whatever) from the derived views.
The LEFT JOIN is in case of no sales in that week.
The ON clause looks at the fiscal calendar AND the week derived view, just in case the derived view describes a week that's not really in that year.
SELECT
p.year_id,
p.period_id,
w.week_id,
SUM(s.amount) AS total_amount
FROM
fiscal_calendar c
CROSS APPLY
(
SELECT period, 1, period1_startDate, period1_endDate
UNION ALL SELECT period, 2, period2_startDate, period2_endDate
..
UNION ALL SELECT period, 13, period13_startDate, period13_endDate
)
AS p(year_id, period_id, startDate, endDate)
CROSS APPLY
(
SELECT 1, DATEADD(d, 0, startDate), DATEADD(d, 6, startDate)
UNION ALL SELECT 2, DATEADD(d, 7, startDate), DATEADD(d, 13, startDate)
UNION ALL SELECT 3, DATEADD(d, 14, startDate), DATEADD(d, 20, startDate)
UNION ALL SELECT 4, DATEADD(d, 21, startDate), DATEADD(d, 27, startDate)
)
AS w(week_id, startDate, endDate)
LEFT JOIN
sales s
ON s.date BETWEEN c.period1_startdate AND c.period13_enddate
AND s.date BETWEEN w.startDate AND w.endDate
WHERE
p.year_id = 2018
AND p.period_id = 1
GROUP BY
p.year_id,
p.period_id,
w.week_id
UNPIVOT is a useful TSQL operator to use when normalizing data. Basically it takes a row and makes new rows - one for each column specified in a list of columns.
In the case below I unpivot on the PeriodX_StartDate columns. I originally did two unpivots, the other on PeriodX_EndDate. The end date was unnecessary, but in case you're wondering how I joined the two unpivots: I used a cross apply to generate a key for each week and had a predicate that tested if they were equal. Without the predicate you get a Cartesian product.
To generate the weeks I used a CROSS APPLY that is very similar to the one in #MatBailie's answer, except I avoided the unions by generating a set of arguments for each week that are passed into functions that generate the dates.
WITH normalizedCal AS (
SELECT [Period], MonthStart, WeekKey, StartDate, CutoffDate
FROM fiscal_calendar cal
UNPIVOT (
MonthStart FOR StartKey IN (Period1_StartDate, Period2_StartDate, ..., PeriodN_StartDate)
) AS startInfo
CROSS APPLY (
SELECT 'WK' + CAST((StartIndex / 7) + 1 AS char(1)) [WeekKey]
, DATEADD(day, startIndex, MonthStart) [StartDate]
, DATEADD(day, EndIndex, MonthStart) [CutoffDate]
FROM (
VALUES ( 0, 7 ), ( 7, 14 ), ( 14, 21 ), ( 21, 28 )
) rangeValues ( StartIndex, EndIndex )
) weekInfo
)
SELECT [Period], MonthStart, WeekKey, COALESCE(SUM(AMOUNT), 0) [Total_Sales]
FROM normalizedCal nc
LEFT JOIN sales ON sales.Date >= nc.StartDate AND sales.Date < nc.CutoffDate
GROUP BY [Period], MonthStart, WeekKey
ORDER BY [Period], MonthStart, WeekKey
Working Example with sample data:
WITH normalizedCal AS (
SELECT [Period], MonthStart, WeekKey, StartDate, CutoffDate
FROM (
VALUES (2018, '2017-12-01', '2017-12-29', '2017-12-30', '2018-01-26')
) cal ([Period], Period1_StartDate, Period1_EndDate, Period2_StartDate, Period2_EndDate)
UNPIVOT (
MonthStart FOR StartKey IN (Period1_StartDate, Period2_StartDate)
) AS startInfo
CROSS APPLY (
SELECT 'WK' + CAST((StartIndex / 7) + 1 AS char(1)) [WeekKey]
, DATEADD(day, startIndex, MonthStart) [StartDate]
, DATEADD(day, EndIndex, MonthStart) [CutoffDate]
FROM (
VALUES ( 0, 7 ), ( 7, 14 ), ( 14, 21 ), ( 21, 28 )
) rangeValues ( StartIndex, EndIndex )
) weekInfo
),
sales AS (
SELECT [Sales_order_no],[Amount], CAST([Date] as DATE) [Date],[Customer]
FROM (VALUES
(111, 20453, '2017-12-03', N'abc'),
(112, 23154, '2017-12-04', N'bbb'),
(113, 20201, '2017-12-10', N'ddd'),
(114, 39012, '2017-12-11', N'ccc'),
(115, 11111, '2017-12-18', N'eee'),
(116, 22222, '2017-12-25', N'uuu')
) [salessrc] ( [Sales_order_no],[Amount],[Date],[Customer])
)
SELECT [Period], MonthStart, WeekKey, COALESCE(SUM(AMOUNT), 0) [Total_Sales]
FROM normalizedCal nc
LEFT JOIN sales ON sales.Date >= nc.StartDate AND sales.Date < nc.CutoffDate
GROUP BY [Period], MonthStart, WeekKey
ORDER BY [Period], MonthStart, WeekKey
according to your provided example, You could do something like this :
SELECT *
FROM (
SELECT
[YEAR] = YEAR([Date]),
[MONTH] = MONTH([Date]),
[WEEK] = DATEPART(week, [Date]) - DATEPART(week, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)),
SUM(Amount) OVER(PARTITION BY YEAR([Date]), DATEPART(week, [Date]) - DATEPART(week, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0))+ 1) AS TotalSales
FROM Sales
)D
GROUP BY
[YEAR],
[MONTH],
[WEEK],
TotalSales
this will give you the same results that you've provided in your example, however, since we don't know how your Fiscal_calendar is configured you will need to see is it a mandatory to link it with it or not.

How do I find last year's WTD(week to date) data in MSSQL?

SO here's I have found TYWTD(this year week to date)
I got the query for this year but I need to know how to write a query for last year 4-5-4 calendar date.
If I pull reports today, then the date range should be following.
this year WTD date range should be 6/11/17 - 6/13/17
last year WTD date range should be 6/12/17 - 6/14/17
Can anyone advise me for last year WTD?
Thank you!
SELECT MAX(te.StoreID) AS StoreID,
SUM(te.Price * te.Quantity) AS Sales,
SUM(te.Cost * te.Quantity) AS Cost,
COUNT(DISTINCT t.TransactionNumber) AS Trxn,
SUM(te.Quantity) AS Quantity
FROM TransactionEntry te
INNER JOIN [Transaction] t
ON te.TransactionNumber = t.TransactionNumber
AND te.StoreID = t.StoreID
LEFT JOIN item i
ON te.itemID = i.ID
LEFT JOIN Department d
ON i.DepartmentID = d.ID
WHERE d.ID <> 8
AND CONVERT(date, t.Time) >= dateadd(day, 1-datepart(dw, getdate()), convert(date, getdate()))
AND CONVERT(date, t.Time) <= dateadd(day, 8-datepart(dw, getdate()), convert(date, getdate()))
GROUP BY te.StoreID) AS TYWTD
Subtracting a year from GetDate() should do the trick.
dateadd(day, 1-datepart(dw, DateAdd(year,-1,getdate())), convert(date, DateAdd(year,-1,getdate())))
This yields 2016-06-12.
Here is the updated script.
Updated again.
SELECT MAX(te.StoreID) AS StoreID,
SUM(te.Price * te.Quantity) AS Sales,
SUM(te.Cost * te.Quantity) AS Cost,
COUNT(DISTINCT t.TransactionNumber) AS Trxn,
SUM(te.Quantity) AS Quantity
FROM TransactionEntry te
INNER JOIN [Transaction] t
ON te.TransactionNumber = t.TransactionNumber
AND te.StoreID = t.StoreID
LEFT JOIN item i
ON te.itemID = i.ID
LEFT JOIN Department d
ON i.DepartmentID = d.ID
WHERE d.ID <> 8
AND CONVERT(date, t.Time) >= dateadd(day, 1-datepart(dw, DateAdd(year,-1,getdate())), convert(date, DateAdd(year,-1,getdate())))
AND dateadd(day, 8-datepart(dw, DateAdd(year,-1,getdate())), convert(date, DateAdd(year,-1,getdate())))
GROUP BY te.StoreID) AS TYWTD

SQL: Daily report for with user counts

I am trying to get the 30 days report of users, that will return date and total count of users as count created on that date and i did it with this query
Select count(*) As [Count] ,
(SELECT CONVERT(date, AddDate)) As [Date]
from Users
WHERE AddDate >= (SELECT DateAdd(month, -1, Convert(date, GetDate())))
Group By CONVERT(date, AddDate)
it give me only those dates on which any user is created, but i want to show all 30 days either if it has count 0.
Same Case i want to do with monthly report.
i am getting months in which users are created , now i want to change it to get last 12 months from this month and their total users count. For this i am using this query
Select count(*) As [Count] ,
(Select DATEPART( month , DateAdd( month , DATEPART(mm,AddDate) , -1 ) )) as Month
from Users
WHERE AddDate >= (SELECT DateAdd(YEAR, -1, Convert(date, GetDate())))
Group By DATEPART(mm,AddDate)
Using a Calendar CTE:
With NumberSequence ( Number ) as
(
Select 1 as Number
union all
Select Number + 1
from NumberSequence
where Number <= 30
)
, CalendarCTE as
(
select cast(dateadd(dd, -30 + Number,getdate()) as Date) as CalDate
from Numbersequence
)
select CalDate, count(U1.*) as CountUsers
from CalendarCTE
left join Users U1
on CalDate = convert(date, U1.AddDate)
group by CalDate
As I mentioned in comment, You need a Calendar table and Left Join
SELECT Count(u.adddate) AS [Count],
c.dates AS [Date]
FROM calendar_table C
LEFT JOIN users U
ON c.dates = CONVERT(DATE, adddate)
WHERE c.dates >= Dateadd(month, -1, CONVERT(DATE, Getdate()))
GROUP BY c.dates
To generate/create a calendar table or dates check out the below questions
How to generate a range of dates in SQL Server
Generate Dates between date ranges
How to create a Calender table for 100 years in Sql
Try this script :
WITH CTEDates
AS
(
SELECT CAST(GetDate() as date) AS [date]
UNION ALL
SELECT DATEADD(dd, 1, [date])
FROM CTEDates
WHERE DAY([date]) <= 30
)
Select count(*) As [Count] ,CONVERT(date, AddDate) As [Date]
from CTEDates
LEFT JOIN Users ON CTEDates.date=CONVERT(date, AddDate)
WHERE AddDate >= DateAdd(month, -1, GetDate())
Group By CONVERT(date, AddDate)
DECLARE #StartDate Datetime
DECLARE #EndDate Datetime
CREATE TABLE #tMyCalanderDate (dtDate Datetime Primary key)
SELECT #StartDate = '01-Sep-2016'
SELECT #EndDate = '30-Sep-2016'
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #tMyCalanderDate (dtDate)
SELECT #StartDate
SELECT #StartDate = DATEADD(day,1,#StartDate)
END
SELECT count(A.UserID) As [Count] , B.dtDate As [Date]
FROM Users AS A
RIGHT JOIN #tMyCalanderDate AS B ON CONVERT(date, A.AddDate) = CONVERT(date, B.dtDate)
WHERE CONVERT(date, A.AddDate) BETWEEN #StartDate AND #EndDate
Group By CONVERT(date, B.dtDate)
You can use a CTE to get a thirty day calendar. Then left join your Users table to it.
DECLARE #CurrentTime DATETIME = GETDATE()
;WITH CTE AS
(
SELECT CONVERT(DATE, #CurrentTime) AS [Date]
UNION ALL
SELECT DATEADD(dd, -1, Date)
FROM CTE
WHERE DATEADD(dd, 29, Date) > #CurrentTime
)
SELECT COUNT(U.AddDate) AS [Count]
, CTE.[Date] AS [Date]
FROM CTE
LEFT JOIN users U
ON CTE.Date = CONVERT(Date, AddDate)
GROUP BY CTE.Date
You can use a similar CTE to get the twelve month calendar and use the same joins to get the count.
HTH.

SQL - Display running count of appointments grouped by time frame

I have a table
tblAppointment {
App_ID,
App_Date,
User_ID }
I currently have a statement that returns number of appointments grouped by year and month
SELECT
YEAR(App_Date) AS Year,
MONTH(App_Date) AS Month,
count(*) AS "No of Appointments"
FROM
tblapplication
GROUP BY
YEAR(App_Date),
MONTH(App_Date)
Im not sure how to write a select statement to return it with headings {time frame, No of applications}, and then have data in
row 1: time frame = week thus far, no of app = x.
row 2: time frame = month thus far, no of app = y.
ro3 3: time frame = year so far, no of app - z.
I would like to know how many appointments there are for 1. the current week, 2. the current month. 3. the current year, And have each result in its own row.
Any help in the right direction would be greatly appreciated. The actual problem is much greater than this but believe I have simplified it to the crux of the matter for now.
If you're okay with the results on one row, it's relatively easy:
select count(case when datepart(wk, App_Date) = datepart(wk, getdate())
then 1 end) as WeekSofFar
, count(case when datepart(m, App_Date) = datepart(m, getdate())
then 1 end) as MonthSofFar
, count(*) as YearSoFar
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
If the separate rows are a must-have, try something like:
select 'WeekSoFar' as Period
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
and datepart(wk, App_Date) = datepart(wk, getdate())
) as NumberOfApps
union all
select 'MonthSoFar'
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
and datepart(m, App_Date) = datepart(m, getdate())
)
union all
select 'YearSoFar'
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
)
I assumed SQL 2008 as you didn't specify.
SELECT
X.TimePeriod,
Count(
CASE X.Which
WHEN 3 THEN
CASE
WHEN App_Date > DateAdd(Day, -DatePart(Weekday, GetDate()), GetDate())
THEN 1
END
WHEN 2 THEN CASE WHEN Month(App_Date) = Month(GetDate()) THEN 1 END
ELSE 1 END
) [No of Appointments]
FROM
tblApplication
CROSS JOIN (
VALUES (1, 'Year to date'), (2, 'Month to date'), (3, 'Week to date')
) X (Which, TimePeriod)
WHERE
App_Date < Convert(date, GetDate() + 1)
AND App_Date >= DateAdd(Year, DateDiff(Year, '19000101', App_Date), '19000101')
GROUP BY
X.Which,
X.TimePeriod
ORDER BY
X.Which
If you have a lot of data in your table and an index on App_Date, this query will perform hugely better than one using date functions on the entire table without filtering.
I also have an embedded assumption that your App_Date values have no time portion (they are all set to 12am). If this is not true please let me know so I can modify case 3 to be correct.
If anyone wants to try the code here's some setup:
CREATE TABLE tblApplication (
App_Date datetime
)
INSERT tblApplication
VALUES
('2/1/2012'), ('2/5/2012'), ('2/10/2012'), ('1/2/2012'), ('1/9/2012'),
('1/15/2012'), ('1/28/2012'), ('12/1/2012'), ('12/5/2012'), ('12/10/2012'),
('11/2/2012'), ('11/9/2012'), ('11/15/2012'), ('11/28/2012')
Sorry about not using 'YYYYMMDD', I wasn't thinking when I typed it out.