【问题标题】:No records for given month in SQL COUNT and GROUP BY MonthSQL COUNT 和 GROUP BY Month 中没有给定月份的记录
【发布时间】:2012-04-04 22:21:29
【问题描述】:

我有以下一组数据:

ID  |  CREATED     |  USER
--------------------------
1   |  2012-01-14  |   XYZ
2   |  2012-03-14  |   XYZ
3   |  2012-03-15  |   XYZ
4   |  2012-03-24  |   ABC
5   |  2012-04-10  |   XYZ
6   |  2012-04-11  |   ABC

我需要一份报告,显示给定用户的 COUNT,但在没有记录的月份中显示 0。

MTH  |  COUNT
-------------
JAN  |   1
FEB  |   0
MAR  |   2
APR  |   1

我设法让它工作,但几个月没有 0 没有记录。到目前为止,我有这个语法会引发错误..

SELECT Month(CREATED), COUNT(SELECT * FROM SEARCHES WHERE USER = 'XYZ')
FROM SEARCHES
GROUP BY Month(CREATED)

【问题讨论】:

    标签: sql gaps-and-islands


    【解决方案1】:

    这是按日期范围分组的一般查询。 @startDate 和 @endDate 定义范围;您可以为用户设置 min(created) 和 max(created) 或某个固定范围。

    CTEmonthlyRange 生成月份表 - 当月的第一天,下个月的第一天。 Searches 稍后通过创建左连接到monthlyRanges。请注意,用户在连接中被过滤,因为这是左连接,在 where 子句中过滤会有效地将其变成内连接。

    declare @startDate datetime
    declare @endDate datetime
    set @startDate = '2012-01-01'
    set @endDate = '2013-01-01'
    
    ; with monthlyRange (startMonth, startNextMonth) as (
      select dateadd (m, datediff (m, 0, @startDate), 0),
             dateadd (m, datediff (m, 0, @startDate) + 1, 0)
      union all
      select dateadd (m, 1, startMonth),
             dateadd (m, 1, startNextMonth)
        from monthlyRange
      where startNextMonth <= dateadd (m, datediff (m, 0, @endDate), 0)
    )
    SELECT Year(monthlyRange.startMonth) Year, 
           Month(monthlyRange.startMonth) Month, 
           COUNT(searches.Created) Count
      FROM monthlyRange 
      left join SEARCHES
        on monthlyRange.startMonth <= Searches.Created
       and monthlyRange.startNextMonth > Searches.Created
       and [USER] = 'XYZ'
    GROUP BY Year(monthlyRange.startMonth), Month(monthlyRange.startMonth)
    order by 1, 2
    

    Here is Sql Fiddle for testing

    【讨论】:

    • 这很棒!也感谢您向我介绍 SQL fiddle。
    【解决方案2】:

    您无法查询不存在的数据。因此,您需要加入列出(或模拟列出)您想要加入的所有月份的表。如何做到这一点取决于您使用的 rdbms。使用 rownum 生成可以转换为月份的列表是一种常见的方法。或者 Postgres 具有生成系列的功能。顺便说一句,我真的不明白为什么子选择在列子句中而不是将过滤器添加到主查询中。

    另见:

    SQL frequency distribution query to count ranges with group-by and include 0 counts

    How to generate list of all dates between sysdate-30 and sysdate+30?

    【讨论】:

      【解决方案3】:

      试试这个:

      CREATE TABLE #DaTable(
        ID    INT,
        CREATED   DATE,
        USER_ VARCHAR(10)
      )
      INSERT INTO #DaTable(ID, CREATED, USER_) VALUES
      (1  , '2012-01-14', 'XYZ'),
      (2   ,  '2012-03-14'  ,   'XYZ'),
      (3   ,  '2012-03-15'  ,   'XYZ'),
      (4   ,  '2012-03-24'  ,   'ABC'),
      (5   ,  '2012-04-10'  ,   'XYZ'),
      (6   ,  '2012-04-11'  ,   'ABC')
      
      CREATE TABLE #DaMonths(
        Nr    INT,
        Name  VARCHAR(10)
      )
      INSERT INTO #DaMonths(Nr, Name) VALUES
      (1, 'Jan'),
      (2, 'Feb'),
      (3, 'Mar'),
      (4, 'Apr'),
      (5, 'May'),
      (6, 'Jun'),
      (7, 'Jul'),
      (8, 'Aug'),
      (9, 'Sep'),
      (10, 'Oct'),
      (11, 'Nov'),
      (12, 'Dec')
      
      SELECT M.Nr, M.Name, COUNT(DT.ID) as Count_
      FROM #DaMonths as M
        LEFT OUTER JOIN #DaTable as DT ON
          M.Nr = Month(DT.CREATED)
      GROUP BY M.Nr, M.Name
      ORDER BY M.Nr
      

      【讨论】:

        猜你喜欢
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 2015-01-22
        • 2012-02-17
        • 2012-12-28
        • 1970-01-01
        • 2016-04-03
        • 1970-01-01
        相关资源
        最近更新 更多