SQL select, pad with chronological missing months

Please note that there are SQLno 2015-02and tags at the end of the next group 2015-03. If there is no data for the month, I want to show the month and 0. Does anyone know how to do this?

SELECT convert(char(7), MeterReadDate, 121),count(*)
FROM [myTable]
where (MeterReadDate > dateadd(d,-356,getdate()))
group by  convert(char(7), MeterReadDate, 121)
order by  convert(char(7), MeterReadDate, 121)

Sample data:

YYYY-MM COUNT
2014-06 23
2014-07 42
2014-08 80
2014-09 92
2014-10 232
2014-11 88
2014-12 8
2015-01 5
2015-04 2
2015-05 1

Still unable to clear the missing lines, this is where I am with it.

DECLARE @StartDate DATETIME = dateadd(m,-12,getdate()), @EndDate DATETIME = getdate(), @DATE DATETIME

DECLARE @TEMP AS TABLE (MeterReadDate datetime)

SET @DATE = @StartDate

WHILE @DATE <= @EndDate
BEGIN
     INSERT INTO @TEMP VALUES ( @DATE)
    SET @DATE = DATEADD(MONTH,1,@DATE)
END



SELECT convert(char(7), t.MeterReadDate, 121),count(*)

  FROM @TEMP m left join
     [myTable] t
     on convert(char(7), t.MeterReadDate, 121) = convert(char(7), m.MeterReadDate, 121)

  where (t.MeterReadDate > dateadd(m,-12,getdate()))
  group by  convert(char(7), t.MeterReadDate, 121)
  order by  convert(char(7), t.MeterReadDate, 121)
+4
source share
3 answers

If you do not want to go beyond your dates minand maxyour results, 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 )
+2
source

You need a date / month list covering the entire period. Here is one method using 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);
+2
source

The best way to do this is to join a table containing calendar information, one way to do this without actually changing the database schema (and more dynamic, in my opinion) would be to use a table variable and DATEADD().

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

Install @Startand @Endon the dates of your choice, then simply join your set of results!

UPDATE:

To retrieve a date in the format specified above in the "Data Examples" section, which means that you can join the table, use:

SELECT 
CONCAT(YEAR([DATE]),'-',right('0' + cast(month([DATE]) as varchar),2)) 
FROM @TEMP
LEFT JOIN MyTable ON...
0
source

All Articles