【问题标题】:SQL Server Non-Standard Date Based HistogramSQL Server 非标准基于日期的直方图
【发布时间】:2009-05-06 17:42:10
【问题描述】:

我有带有时间戳的用户登录数据,我想做的是按年份获取登录的直方图,但年份从任意日期开始。例如,我想要以下类型的信息:

1 May 2005 - 30 Apr 2006 | 525
1 May 2006 - 30 Apr 2007 | 673
1 May 2007 - 30 Apr 2008 | 892
1 May 2006 - 30 Apr 2009 | 1047

第一列中的标签不重要,但日期范围很重要。我知道我可以通过以下方式将其分解:

SELECT YEAR([date]) AS [year], COUNT(*) AS cnt 
FROM logins
GROUP BY YEAR([date])
ORDER BY [year]

但这并没有给我想要的数据范围。如何做到这一点?

【问题讨论】:

    标签: sql sql-server reporting data-mining


    【解决方案1】:
    declare @baseDate datetime
    set @baseDate = '1 May 2005'
    
    SELECT
        datediff(year, @baseDate, [date]) AS YearBucket 
        ,COUNT(*) AS cnt 
    FROM logins
    GROUP BY datediff(year, @baseDate, [date])
    ORDER BY datediff(year, @baseDate, [date])
    

    编辑 - 抱歉,你是对的。这是一个固定版本(我应该使用测试表开始......)

    create table logins (date datetime, foo int)
    insert logins values ('1 may 2005', 1)
    insert logins values ('1 apr 2006', 2)
    insert logins values ('1 may 2006', 3)
    
    declare @baseDate datetime
    set @baseDate = '1 May 2005'
    
    SELECT
        datediff(day, @baseDate, [date]) / 365 AS YearBucket 
        ,COUNT(*) AS cnt 
    FROM logins
    GROUP BY datediff(day, @baseDate, [date]) / 365
    ORDER BY datediff(day, @baseDate, [date]) / 365
    

    如果您想要比天更多的粒度,请更改日期差异单位。

    编辑 #2 - 好的,这是一个更强大的解决方案,可以处理闰年 :) 编辑#3 - 实际上这不处理闰年,而是允许指定可变的时间间隔。使用 dateadd(year, 1, @baseDate) 获取闰年安全方法。

    declare @baseDate datetime, @interval datetime
    --@interval is expressed as time above 0 time (1/1/1900)
    select @baseDate = '1 May 2005', @interval = '1901'
    
    declare @timeRanges table (beginIntervalInclusive datetime, endIntervalExclusive datetime)
    declare @i int
    set @i = 1
    while @i <= 10
    begin
        insert @timeRanges values(@baseDate, @baseDate + @interval)
        set @baseDate = @baseDate + @interval
        set @i = @i + 1
    end
    
    SELECT
        tr.beginIntervalInclusive,
        tr.endIntervalExclusive,
        COUNT(*) AS cnt 
    FROM logins join @timeRanges as tr
        on logins.date >= tr.beginIntervalInclusive
            and logins.date < tr.endIntervalExclusive
    GROUP BY  tr.beginIntervalInclusive, tr.endIntervalExclusive
    ORDER BY  tr.beginIntervalInclusive
    

    【讨论】:

    • 给出完全相同的结果,只是没有前面的年份。
    • @cdeszaq - 你是对的,对此感到抱歉。查询现在已修复,我应该使用测试表开始..
    • :) 我自己也刚搞定...但它会正确处理闰年,还是会引入 off-by-1 错误?
    • @cdeszaq - 好的,这是一个更强大的解决方案 :)
    • 如此接近...在 2005 年 1 月 1 日仍相差 1...结束间隔设置为 12 月 31 日,而不是 2008 年的明年 1 月 1 日
    【解决方案2】:

    如果您能找到一种方法在单独的表格中定义日期范围,则选择一个标签和两列日期,然后根据您的表格从主查询中加入类似这样的内容。

    Select Count(*) as NoLogons, DateRangeLabel
    From logins a
    inner join
    (
    Select
    DateRangeLabel, StartDate, EndDate
    From tblMyDates 
    ) b
    on a.date between b.startdate and b.enddate
    Group by DateRangeLabel
    

    【讨论】:

      猜你喜欢
      • 2019-08-01
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 2014-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多