【问题标题】:How do you group by any time based interval?您如何按任何基于时间的间隔进行分组?
【发布时间】:2017-06-13 23:37:34
【问题描述】:

在 SQL SERVER 中,如何按任何基于时间的间隔进行分组?

为了节省时间,我想出了这个解决方案,对我来说效果很好。您可以生成任何时基,然后按任何间隔分组。非常适合做时间加权平均。如果有人有更好的方法,我很乐意听取您的意见。

小时

declare @startdate datetime2
declare @enddate datetime2
declare @interval int
set @startdate = '2017-01-01 00:00:00'
set @enddate   = '2017-01-31 00:00:00'
set @interval = 4 --Group by Every 4 hours
;with 
ALL_INTERVALS 
AS (
    SELECT TOP (DATEDIFF(HOUR,@startdate,@enddate))
    TIMES = DATEADD(HOUR,CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])),@startdate),
    1 AS VALUE
        FROM sys.all_objects AS s1
        CROSS JOIN
        sys.all_objects AS s2
)
select DATEADD(HOUR,((DATEDIFF(HOUR, @startdate,TIMES)/@interval)*@interval),@startdate) AS TIMES,SUM(VALUE) AS TESTDATA 
from ALL_INTERVALS
group by DATEADD(HOUR,((DATEDIFF(HOUR, @startdate,TIMES)/@interval)*@interval),@startdate)
order by DATEADD(HOUR,((DATEDIFF(HOUR, @startdate,TIMES)/@interval)*@interval),@startdate)

分钟

注意。 您可以将间隔设置为 60 以实现小时,1440 以实现天....

declare @startdate datetime2
declare @enddate datetime2
declare @interval int
set @startdate = '2017-01-01 00:00:00'
set @enddate   = '2017-01-31 00:00:00'
set @interval = 7
;with 
ALL_INTERVALS 
AS (
    SELECT TOP (DATEDIFF(MINUTE,@startdate,@enddate))
    TIMES = DATEADD(MINUTE,CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id])),@startdate),
    1 AS VALUE
        FROM sys.all_objects AS s1
        CROSS JOIN
        sys.all_objects AS s2
)
select DATEADD(MINUTE,((DATEDIFF(MINUTE, @startdate,TIMES)/@interval)*@interval),@startdate) AS TIMES,SUM(VALUE) AS TESTDATA 
from ALL_INTERVALS
group by DATEADD(MINUTE,((DATEDIFF(MINUTE, @startdate,TIMES)/@interval)*@interval),@startdate)
order by DATEADD(MINUTE,((DATEDIFF(MINUTE, @startdate,TIMES)/@interval)*@interval),@startdate)

【问题讨论】:

    标签: sql-server sql-server-2014


    【解决方案1】:

    我认为你把事情复杂化了。
    您可以使用GROUP BY (DATEDIFF(MINUTE, '2017-01-01', TheDateTime) / 30 每 30 分钟进行一次分组。当然,我选择的日期只是一个随机日期。如果需要,您可以选择示例数据中的第一个(或最后一个)日期。
    您还可以使用此技术获取任何时间部分的每个间隔 - 只需将关键字 MINUTE 更改为您想要使用的任何日期部分,并将 intreval 30 更改为您想要的任何间隔。

    考虑以下示例数据:

    ;WITH CTE AS 
    (
        SELECT CAST('2017-01-01T00:00:00' as datetime) As TheDateTime, 0 as rn
        UNION ALL
        SELECT DATEADD(MINUTE, 1, TheDateTime), rn + 1
        FROM CTE
        WHERE rn < 60
    )
    
    SELECT TheDateTime, rn INTO #T
    FROM CTE
    OPTION(MAXRECURSION 0)
    

    #T 现在包含以下数据:

    TheDateTime                 rn
    2017-01-01 00:00:00.000     0
    2017-01-01 00:01:00.000     1
    2017-01-01 00:02:00.000     2
    2017-01-01 00:03:00.000     3
    ...
    2017-01-01 00:59:00.000     59
    2017-01-01 01:00:00.000     60
    

    要获得按 30 分钟分组的最大 rn,您只需要这样:

    SELECT DATEDIFF(MINUTE, '2017-01-01', TheDateTime) / 30, MAX(rn)
    FROM #T
    GROUP BY DATEDIFF(MINUTE, '2017-01-01', TheDateTime) / 30
    

    结果:

    interval    max_rn
    0           29
    1           59
    2           60
    

    【讨论】:

    • 当可能需要亚分钟粒度并且DATEDIFF 跨度不超过大约 30 年时,也可以使用秒。
    • 这太好了,非常感谢您的发帖。我的 Select all sys 对象在开始日期和结束日期相差 3 或 4 年后中断。您的每次都有效。
    猜你喜欢
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多