如何在SQL中查询每x个月的数据?

时间:2015-06-17 14:20:41

标签: sql sql-server

我有一个表格,显示链接上的点击数,每天都有一个“来源”列

hitdate      originid    hitcount
==================================
2011-01-05          2          25
2011-01-05          3           3
2011-04-06          2           1          
2011-04-06          6          11
2011-05-06          7           9
2011-05-09          2          25
2011-07-10          3           3
2011-17-11          2           1          
2011-01-12          6          11
2012-01-06          7           9

我想要的是以编程方式为每个originID总计每个3个月的hitcount,自该集合的第一天(2011年5月1日)到今天的日期

我想要的结果

Trimester                 originid    hitcount
==============================================
2011-01-05 to 2011-31-07         1           0
                                 2          26 
                                 3           3
                                 6          11
2011-01-08 to 2011-31-10        ..          ..

3 个答案:

答案 0 :(得分:2)

我认为使用datepart(qq, ...作为其他答案的一个可能的麻烦来源是(1)这似乎没有说明日期设置跨越多年的可能性,以及(2)它对数据集中最早的日期做出假设。我已经尝试编写一个适用于任何开始日期的解决方案,即使它不是一个月的第一天。它有点复杂,所以也许有人可以建议一种简化它的方法。

-- Sample data from the question. 
declare @hits table (hitdate date, originid bigint, hitcount int);
insert @hits values
    (convert(date, '20110501', 112), 2, 25),
    (convert(date, '20110501', 112), 3,  3),
    (convert(date, '20110604', 112), 2,  1),
    (convert(date, '20110604', 112), 6, 11),
    (convert(date, '20110605', 112), 7,  9),
    (convert(date, '20110905', 112), 2, 25),
    (convert(date, '20111007', 112), 3,  3),
    (convert(date, '20111117', 112), 2,  1),
    (convert(date, '20111201', 112), 6, 11),
    (convert(date, '20120601', 112), 7,  9);

-- Define the date range that we're concerned with.
declare @beginDate date, @endDate date;
select
    @beginDate = min(hitdate),
    @endDate = convert(date, getdate())
from 
    @hits;

-- Build a list of three-month periods that encompass the date range defined
-- above. Each period will be inclusive on the lower end of the range and
-- exclusive on the upper end.
declare @Trimester table (beginDate date, endDate date);
while @beginDate <= @endDate
begin
    insert @Trimester values (@beginDate, dateadd(m, 3, @beginDate));
    set @beginDate = dateadd(m, 3, @beginDate);
end;

-- Finally, assign each hit to one of these periods.
select
    [Trimester] = 
        convert(varchar, T.beginDate) + 
        ' to ' + 
        convert(varchar, dateadd(d, -1, T.endDate)),
    H.originid,
    hitcount = sum(H.hitcount)
from
    @hits H
    inner join @Trimester T on 
        H.hitdate >= T.beginDate and
        H.hitdate < T.endDate
group by
    T.beginDate,
    T.endDate,
    H.originid
order by
    T.beginDate,
    H.originid;

结果集是:

Query results

我的结果集与您的结果集之间的一个区别是,您的结果集包含一条条目,表示originid = 1的点击次数为零。我没有做过任何事情,因为我不知道你在哪里存储有效的originid值集合,但如果你愿意,你可以很容易地调整这个查询以支持它,只是在最后一步中插入联接。

更新:关于使用datepart的问题,请多说一点:

  • 使用datepart(qq, hitdate)本身假设季度边界是日历季度,例如6月1日至6月30日,正如另一个答案中已经提到的那样。

  • 使用类似datepart(qq, dateadd(mm,1,hitdate))之类的内容会将季度更改为一个月,因此您可以在5月1日开始使用,就像您的示例数据一样,但假设您想在6月而不是5月开始。您必须更改查询。

  • datepart(qq, ...本身将为同一季度但不同年份的两个日期返回相同的值。所以2011年5月1日的点击和2012年5月1日的点击将被组合在一起。您可以对此进行调整,但在撰写本文时,其他答案并未这样做。

  • 以上述任何方式使用datepart都假设季度从一个月的第一天开始。假设结果集中最早的日期是5月15日。我的查询将于5月15日至8月14日为第一季度,8月15日至11月14日为第二季度等。

如果你想要一个使用datepart(qq, ...)的解决方案,我认为最后一个可能是最难克服的。如果您对开始日期始终是一个月的第一天的假设感到满意,那么可以使用比我建议的更简单的解决方案。

在上面的查询中,如果您想使用其他开始日期,只需将日期指定为@beginDate

答案 1 :(得分:1)

使用Group BYDATEPART

SELECT DATEPART(qq,hitdate) AS Trimester, originid, SUM(hitcount)
FROM yourtable
GROUP BY DATEPART(qq,hitdate), originid

答案 2 :(得分:1)

使用DATEPART将日期分成四分之一。由于您的3个月期间不是标准季度(1月至3月,4月至6月),您可以使用DATEADD来抵消您的命中日期,以便它在相应的三个月内落入:

Select DATEPART(qq,dateadd(mm,1,hitdate)) as QRTR, originid, SUM(hitcount)
from tablename
group by DATEPART(qq,dateadd(mm,1,hitdate)), originid