Notice the 2015-02
and 2015-03
months are missing in the output from the following group by SQL
. If there is no data for a month I wan
If you don't want to go beyond your min
and max
dates of your results then you can do the following:
WITH cte
AS ( SELECT convert(char(7), MeterReadDate, 121) AS [Date], COUNT(*) AS [Count]
FROM [myTable]
WHERE (MeterReadDate > dateadd(d,-356,getdate()))
GROUP by convert(char(7), MeterReadDate, 121)
),
minmax
AS ( SELECT CAST(MIN([Date] + '-01') AS DATE) AS mind ,
CAST(MAX([Date] + '-01') AS DATE) maxd
FROM cte
),
calendar
AS ( SELECT mind ,
CONVERT(CHAR(7), mind, 121) AS cmind
FROM minmax
UNION ALL
SELECT DATEADD(mm, 1, calendar.mind) ,
CONVERT(CHAR(7), DATEADD(mm, 1, calendar.mind), 121)
FROM calendar
CROSS JOIN minmax
WHERE calendar.mind < minmax.maxd
)
SELECT c.cmind AS [Date],
ISNULL(cte.[Count], 0) AS [Count]
FROM calendar c
LEFT JOIN cte ON c.cmind = cte.[Date]
OPTION ( MAXRECURSION 0 )
You need a list of dates/months that covers the entire period. Here is one method using a recursive CTE:
with months as (
select cast(getdate() - 365) as thedate
union all
select date_add(1, month, thedate)
from months
where thedate <= getdate()
)
select convert(char(7), m.thedate, 121) as yyyy-mm, count(t.MeterReadDate)
from months m left join
[myTable] t
on convert(char(7), MeterReadDate, 121) = convert(char(7), m.thedate, 121)
group by convert(char(7), m.thedate, 121)
order by convert(char(7), m.thedate, 121);
The best way to do this would be to join onto a table containing calendar information, one way to do this without actually altering the database schema (and is more dynamic in my opinion) would be to use a table variable and the DATEADD()
function.
DECLARE @StartDate DATETIME = '2015-01-01', @EndDate DATETIME = '2015-12-01', @DATE DATETIME
DECLARE @TEMP AS TABLE ([DATE] DATETIME)
SET @DATE = @StartDate
WHILE @DATE <= @EndDate
BEGIN
INSERT INTO @TEMP VALUES (@DATE)
SET @DATE = DATEADD(MONTH,1,@DATE)
END
SELECT * FROM @TEMP
Set @Start
and @End
to your required dates, then just join onto your results set!
UPDATE:
To extract the date in the format you gave above under "sample data", meaning you would be able to join onto the table, use:
SELECT
CONCAT(YEAR([DATE]),'-',right('0' + cast(month([DATE]) as varchar),2))
FROM @TEMP
LEFT JOIN MyTable ON...