SQL COUNT和GROUP BY Month中没有给定月份的记录

时间:2012-04-04 22:21:29

标签: sql gaps-and-islands

我有以下数据集:

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)

3 个答案:

答案 0 :(得分:2)

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

另见:

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?

答案 1 :(得分:1)

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

CTE monthlyRange生成月份表 - 当月的第一个月,下个月的第一个月。搜索稍后通过创建左连接到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

答案 2 :(得分:0)

试试这个:

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