SQL Group Distinct Count

时间:2011-05-10 01:44:02

标签: asp.net sql sql-server tsql aggregate-functions

我有下表

User ID    Start Date   End Date
-------------------------------------
John Doe   Mar 11 2011  May 28 2011
Robret S   Mar 21 2011  Jun 29 2011
Tina T     Feb 01 2011  August 20 2011

我想表明过去6个月我有多少人,即使这个月没有人。这怎么可能。我知道我必须进行分组并使用不同的计数。

预期产出:

February  = 1 Resource
March     = 3 Resources
April     = 3 Resources
May       = 3 Resources
June      = 2 Resources
July      = 1 Resource
August    = 1 Resource

4 个答案:

答案 0 :(得分:2)

With Calendar As
    (
    Select Cast('20110501' As DateTime) As [Date]
    Union All
    Select DateAdd(m,-1,[Date])
    From Calendar
    Where [Date] > DateAdd(m,-5,'20110501')
    )
Select DateName(m, C.Date) + ' ' + Cast(Year(C.Date) As char(4))
    , Case Count(*)
        When 1 Then Cast(Count(*) As varchar(10)) + ' Resource'
        Else Cast(Count(*) As varchar(10)) + ' Resources'
        End
From Calendar As C
    Left Join MyTable As T
        On C.Date Between T.StartDate And T.EndDate
Group By C.Date

结果:

December 2010   | 1 Resource
January 2011    | 1 Resource
February 2011   | 1 Resource
March 2011      | 1 Resource
April 2011      | 3 Resources
May 2011        | 3 Resources

答案 1 :(得分:0)

您将需要过去6个月的现有数据记录,以便您可以合并这两组数据。您可以在CTE中生成最近6个月,并对您的数据进行左连接。即使您没有数据,也可以显示最近6个月。

答案 2 :(得分:0)

我不认为你可以使用“简单”的选择语句(甚至使用GROUPing等)来做你想做的事。以下是我的头脑,所以你必须尝试一下,最好阅读Joe Celko的优秀SQL for Smarties书。

您需要创建一个包含所有月份(开始/结束日期)的第二个表格。您只需要一个表用于所有类型的类似查询,并且它必须包含您对查询感兴趣的日期范围中的所有月份:

CREATE TABLE months (id, start DATE, end DATE);

INSERT INTO months (id, start, end) 
          values ( (1, 2011-01-01, 2011-01-31), 
                   (2, 2011-02-01, 2011-02-28), ...);

然后将用户表中的OUTER OUTER JOIN转到此月份表。这将为每个用户提供他们可用的每个月的行,您可以根据需要进行GROUP:

SELECT months.id, COUNT(user.id) 
  FROM months LEFT OUTER JOIN users 
         ON user.start_date < months.end 
        AND user.end_date > months.start 
GROUP BY months.id;

希望有所帮助。

答案 3 :(得分:0)

WITH resources AS (
  SELECT
    Date = DATEADD(month, v.number, [Start Date])
  FROM atable t
    INNER JOIN master.dbo.spt_values v ON v.type = 'P'
      AND v.number BETWEEN 0 AND DATEDIFF(month, t.[Start Date], t.[End Date])
)
SELECT
  Month = DATENAME(month, Date),
  ResourceCount = CAST(COUNT(*) AS varchar(30)) +
                  CASE COUNT(*) WHEN 1 THEN ' Resource' ELSE ' Resources' END
FROM resources
WHERE Date > DATEADD(month, -6, DATEADD(day, -DAY(GETDATE()), GETDATE()))
GROUP BY YEAR(Date), MONTH(Date), DATENAME(month, Date)
ORDER BY YEAR(Date), MONTH(Date)