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

24 人关注

我正试图将一些记录分成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列出现了隐性转换错误。非常感谢任何帮助!

7 个评论
我不太明白你说的'分组到不同的区间'是什么意思。 回顾一下,结果一定是列中的行,你能说明你的数据的样本行会是什么样子吗? 特别是我不清楚,一个人是否会在一个5分钟组中,也在一个15分钟组中,也在一个30分钟组中...等等。 如果每条记录都在4个组中,比如说,你希望结果中的列的名称是什么?
另外,如果你要发布一些sql问题,1)一定要给问题加上具体的服务器类型的标签(我从标题上看到是MS SQL,但如果你使用标签,他们会建议你可以指定一个版本),2)你可以通过花时间建立一个sql fiddle (sqlfiddle.org )来降低 "弄清问题含义的成本";它让你输入你想查询的例子数据。
我想澄清一点:SQL Server中的 DATETIME 从来都不是 以基于字符串的格式存储的--它在内部被存储为两个4字节的INT值。这种格式可能是你的 默认表现形式 --但它 不是 以这种格式存储的!
sample_date 实际上是 datetime 类型的吗?如果是的话,它没有格式(这很好)。
sample_date的类型是(smalldatetime,非空)。
我已经在帖子中加入了sql-server-2008的标签,谢谢你的建议。
我修改了帖子,希望能更好地说明我所说的 "分组到不同区间 "的意思,并增加了结果的例子。基本上,我想运行不同的查询,而不是在同一个表中返回结果。我想如果有可能的话,可能会更好,但我没有考虑到这一点。
sql
sql-server
sql-server-2008
aggregate-functions
jrubengb
jrubengb
发布于 2012-03-22
5 个回答
JotaBe
JotaBe
发布于 2022-04-11
0 人赞同
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
-- this groups by the period and gets the average
    (SELECT
        P.FiveMinutesPeriod,
        AVG(P.Value) AS AvgValue
-- 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
我建议 19900101 而不是 1990-1-1 ,因为指定日期而不指定时间的虚线格式是不明确的。(当然,在这个具体的例子中是可以的,但是如果月和日不同,SQL Server可能会以两种方式之一来解释,或者引发一个转换错误)
谢谢你的建议。我运行了这个查询,它似乎将我的平均值分组到结果中的行中,但我无法让汇总的时间值出现在查询结果中。我编辑了你的帖子,描述了我试图让时间列出现在查询结果中的尝试
我试着使用Damien_The_Unbeliever描述的'19900101'格式,这似乎确实有效,然而我在最初的查询结果中没有看到任何差异。谢谢你的建议。
@jrubengb:使用 DATEADD 和简单的数学方法,从数字中取回日期时间。我已经更新了我的答案。
关于之前对日期格式的评论, YYYY-MM-DDThh:mm:ss ,是ISO格式,在每个SQL Server(和任何其他知道这种格式的软件)中都能普遍理解,并且与语言或任何其他相关设置无关。
DJ Sipe
DJ Sipe
发布于 2022-04-11
0 人赞同

在@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分钟为间隔进行分组,但是,当把数据作为结果的一部分呈现出来时,我只是把间隔计算反过来,得到四舍五入的日期和时间。

引用我自己的话。注意:为了清楚起见,我把它分成了3个子序列。你应该从里到外阅读它。当然,它也可以写成一个单一的、紧凑的查询
chiliNUT
chiliNUT
发布于 2022-04-11
0 人赞同

所以,万一你在谷歌上搜索到这个,但你需要在mysql中进行,这是我的情况。

在MySQL中,你可以做到

GROUP BY
CONCAT(
    DATE_FORMAT(`timestamp`,'%m-%d-%Y %H:'),
    FLOOR(DATE_FORMAT(`timestamp`,'%i')/5)*5
...但问题是关于sql server而不是我的sql?
这个问题是关于 sql-server 的,但它也被标记为普通 sql ,所以这将包括所有的味道。
Arunav dutta gupta
Arunav dutta gupta
发布于 2022-04-11
0 人赞同

这将有助于实现你的目标

替换 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