SQL select, pad with chronological missing months

前端 未结 3 666
Happy的楠姐
Happy的楠姐 2020-12-21 02:22

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

相关标签:
3条回答
  • 2020-12-21 02:49

    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 )
    
    0 讨论(0)
  • 2020-12-21 02:49

    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);
    
    0 讨论(0)
  • 2020-12-21 03:05

    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...
    
    0 讨论(0)
提交回复
热议问题