将日期时间分组为 5、15、30 和 60 分钟间隔

问题描述 投票:0回答:7

我正在尝试将一些记录分为 5、15、30 和 60 分钟的间隔:

SELECT AVG(value) as "AvgValue",
sample_date/(5*60) as "TimeFive"
FROM DATA
WHERE id = 123 AND sample_date >= 3/21/2012

我想运行多个查询,每个查询都会将我的平均值分组为所需的时间增量。因此 5 分钟的查询将返回如下结果:

AvgValue  TimeFive
6.90      1995-01-01 00:05:00
7.15      1995-01-01 00:10:00
8.25      1995-01-01 00:15:00

30 分钟的查询将导致以下结果:

AvgValue  TimeThirty 
6.95      1995-01-01 00:30:00
7.40      1995-01-01 01:00:00

datetime
列采用
yyyy-mm-dd hh:mm:ss
格式

我的

datetime
列出现隐式转换错误。非常感谢任何帮助!

sql sql-server sql-server-2008 aggregate-functions
7个回答
31
投票

使用

datediff(minute, '1990-01-01T00:00:00', yourDatetime)

将为您提供自 1990-1-1 以来的分钟数(您可以使用所需的基准日期)。

然后您可以除以 5、15、30 或 60,并按该除法的结果进行分组。 我已经检查过它将被评估为整数除法,因此您将得到一个可用于分组的整数。

group by datediff(minute, '1990-01-01T00:00:00', yourDatetime) /5

更新由于原始问题被编辑为要求数据在分组后以日期时间格式显示,我添加了这个简单的查询,它将执行OP想要的操作:

-- This convert the period to date-time format
SELECT 
    -- note the 5, the "minute", and the starting point to convert the 
    -- period back to original time
    DATEADD(minute, AP.FiveMinutesPeriod * 5, '2010-01-01T00:00:00') AS Period,
    AP.AvgValue
FROM
    -- this groups by the period and gets the average
    (SELECT
        P.FiveMinutesPeriod,
        AVG(P.Value) AS AvgValue
    FROM
        -- This calculates the period (five minutes in this instance)
        (SELECT 
            -- note the division by 5 and the "minute" to build the 5 minute periods
            -- the '2010-01-01T00:00:00' is the starting point for the periods
            datediff(minute, '2010-01-01T00:00:00', T.Time)/5 AS FiveMinutesPeriod,
            T.Value
        FROM Test T) AS P
    GROUP BY P.FiveMinutesPeriod) AP

注意:为了清楚起见,我将其分为 3 个子查询。你应该从内到外阅读它。当然,它可以写成一个单一的、紧凑的查询

注意:如果您更改周期和开始日期时间,您可以获得所需的任何间隔,例如从给定日期开始的周数,或您需要的任何内容

如果您想为此查询生成测试数据,请使用:

CREATE TABLE Test
( Id INT IDENTITY PRIMARY KEY,
Time DATETIME,
Value FLOAT)

INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:00:22', 10)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:03:22', 10)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:04:45', 10)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:07:21', 20)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:10:25', 30)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:11:22', 30)
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:14:47', 30)

执行查询的结果是这样的:

Period                     AvgValue
2012-03-22 00:00:00.000    10
2012-03-22 00:05:00.000    20
2012-03-22 00:10:00.000    30

19
投票

基于@JotaBe的答案(我无法评论——否则我会),你也可以尝试这样的方法,不需要子查询。

 SELECT 
    AVG(value) AS 'AvgValue',

    -- Add the rounded seconds back onto epoch to get rounded time
    DATEADD(
        MINUTE,
        (DATEDIFF(MINUTE, '1990-01-01T00:00:00', your_date) / 30) * 30,
        '1990-01-01T00:00:00'
    )      AS 'TimeThirty'

 FROM YourTable
 -- WHERE your_date > some max lookback period
 GROUP BY
    (DATEDIFF(MINUTE, '1990-01-01T00:00:00', your_date) / 30)

此更改删除了临时表和子查询。它使用相同的核心逻辑按 30 分钟间隔进行分组,但是,当将数据作为结果的一部分呈现回来时,我只是反转间隔计算以获得四舍五入的日期和时间。


9
投票

所以,万一你用谷歌搜索了这个,但你需要在 mysql 中完成它,这就是我的情况:

在 MySQL 中你可以做

GROUP BY
CONCAT(
    DATE_FORMAT(`timestamp`,'%m-%d-%Y %H:'),
    FLOOR(DATE_FORMAT(`timestamp`,'%i')/5)*5
)

4
投票

在新的 SQL Server 2022 中,您可以使用

DATE_BUCKET
,这会将其向下舍入到指定的最接近的间隔。

SELECT
  DATE_BUCKET(minute, 5, d.sample_date) AS TimeFive,
  AVG(d.value) AS AvgValue  
FROM DATA d
WHERE d.id = 123
  AND d.sample_date >= '20121203'
GROUP BY
  DATE_BUCKET(minute, 5, d.sample_date);

0
投票

您可以使用以下语句,这删除了第二个组成部分并计算距五分钟标记的分钟数,并使用它向下舍入到时间块。如果您想更改窗口,这是理想的选择,您只需更改 mod 值即可。

select dateadd(minute, - datepart(minute,  [YOURDATE]) % 5, dateadd(minute, datediff(minute, 0, [YOURDATE]), 0)) as [TimeBlock]

0
投票

@chiliNUT 的建议正是我正在寻找的,并且我认为与 OP 问题相匹配。 完美的代码,超级简单。


-1
投票

这将完全满足您的需求

替换

dt
- 您的日期时间
c
- 呼叫字段
astro_transit1
- 您的表 300 参考 5 分钟,因此每次添加 300 以增加时间间隙

SELECT FROM_UNIXTIME( 300 * ROUND( UNIX_TIMESTAMP( r.dt ) /300 ) ) AS 5datetime, ( SELECT r.c FROM astro_transit1 ra WHERE ra.dt = r.dt ORDER BY ra.dt DESC LIMIT 1 ) AS first_val FROM astro_transit1 r GROUP BY UNIX_TIMESTAMP( r.dt ) DIV 300 LIMIT 0 , 30
© www.soinside.com 2019 - 2024. All rights reserved.