按时间汇总记录

时间:2014-01-30 10:01:55

标签: mysql

我有一个查询来按时间执行聚合记录,但我有一些错误。

我的情况:我将MySQL db 5.6中的股票市场数据存储在从0900到1730的每分钟一条记录中,即每天511条记录

enter image description here

我需要在不同的时间范围内汇总这些数据,假设为5分钟,那么

volume5min - >总量0900:0904

open5min - > 0900记录的开放值(范围内的第一个开放值)

close5min - > 0904记录的近似值(范围内的最后一个接近值)

high5min - > 0900至0904范围内的最高值

low5min - > 0900至0904范围内的最低值

等等。

我有一个查询来完成此操作,但是我在打开和关闭聚合值时出现错误

SELECT 
    floor(cast(time as SIGNED) / 5) as timeInterval,
    date,
    time,
    MAX(high) AS high,
    MIN(low) as low,
    SUM(volume) as volume,
    (select 
            open
        from
            atlantia a2
        where
            a1.time = a2.time
        order by time
        limit 1) as open,
    (select 
            close
        from
            atlantia a2
        where
            a1.time = a2.time
        order by time desc
        limit 1) as close
FROM
    atlantia a1
GROUP BY date , timeInterval

这是我执行查询的原因

enter image description here

打开和关闭没有正确聚合,而其他列似乎很好。

更重要的是,更改总时间范围我得到的时间不正确,例如下面的60分钟示例

enter image description here

从0900开始我应该有1000,1100等等,而现在我也有1020,1140等。

列类型为:

日期:CHAR 时间:CHAR 所有其余的都是DOUBLE但是Volume是INTEGER。

如何修改此查询以正确汇总值?

编辑:为了验证您的上一次查询,我手动检查了任何一个小时,这些是我应该得到的正确值

enter image description here

您的查询会返回关闭值的差异,其余的都没关系

enter image description here

关闭值应该是时间范围的最后一条记录,即0900和0959之间的时间关闭是关闭列中的0959值。

编辑2:看来我已经找到了诀窍的所在,现在有了这个查询,一切正常

 SELECT 
 Sub1.timeInterval, 
 a1.date,
 MIN(a1.time),
 MAX(a1.high) AS high,
 MIN(a1.low) as low,
 SUM(a1.volume) as volume,
 a2.open as open,
 a3.close as close
 FROM atlantia a1
 INNER JOIN
 (
 SELECT floor( (cast( SUBSTRING(time,1,2) AS SIGNED ) * 60 + cast( SUBSTRING(time,3,2)   AS SIGNED )) /60 ) AS timeInterval, MIN(time) AS minTime, MAX(time) AS maxtime
 FROM atlantia
 GROUP BY timeInterval
 ) Sub1
 ON floor( (cast( SUBSTRING(a1.time,1,2) AS SIGNED ) * 60 + cast( SUBSTRING(a1.time,3,2)    AS SIGNED )) /60 ) = Sub1.timeInterval
 INNER JOIN atlantia a2 ON a2.time = Sub1.minTime AND a1.date = a2.date
 INNER JOIN atlantia a3 ON a3.time = Sub1.maxtime AND a1.date = a3.date
 GROUP BY a1.date , timeInterval

如果我想在不同的时间范围内聚合,即5分钟怎么办?我只用/ 5改变/ 60?

由于

1 个答案:

答案 0 :(得分:1)

我可以发现一些问题。

您正在将时间存储在角色字段中,当投射时,签名时间为10点20分被视为1020而不是10 * 60分钟+20分钟。因此当除以60时10:00是16而10:20是17时,因此在你的代码中它们是2个不同的时间间隔。

另一个问题是您已将时间作为字段返回,而不在GROUP BY子句中指定。它将返回的时间值来自未确定的行(通常是第一行但不总是)。可能最容易指定MIN(时间)。

SELECT 
    floor( (cast( SUBSTRING(time,1,2) AS SIGNED ) * 60 + cast( SUBSTRING(time,3,2) AS SIGNED )) /60 ) AS timeInterval, 
    date,
    MIN(time),
    MAX(high) AS high,
    MIN(low) as low,
    SUM(volume) as volume,
    (select 
            open
        from
            atlantia a2
        where
            a1.time = a2.time
        order by time
        limit 1) as open,
    (select 
            close
        from
            atlantia a2
        where
            a1.time = a2.time
        order by time desc
        limit 1) as close
FROM
    atlantia a1
GROUP BY date , timeInterval

可以清理sql以删除子查询。

修改

有一个游戏,这可能会这样做,但不确定效率,没有表我无法测试: -

SELECT 
    Sub1.timeInterval, 
    a1.date,
    MIN(a1.time),
    MAX(a1.high) AS high,
    MIN(a1.low) as low,
    SUM(a1.volume) as volume,
    MIN(a2.open) as open,
    MIN(a3.close) as close
FROM atlantia a1
INNER JOIN
(
    SELECT floor( (cast( SUBSTRING(time,1,2) AS SIGNED ) * 60 + cast( SUBSTRING(time,3,2) AS SIGNED )) /60 ) AS timeInterval, MIN(time) AS minTime, MAX(time) AS maxtime
    FROM atlantia
    GROUP BY timeInterval
) Sub1
ON floor( (cast( SUBSTRING(a1.time,1,2) AS SIGNED ) * 60 + cast( SUBSTRING(a1.time,3,2) AS SIGNED )) /60 ) = Sub1.timeInterval
INNER JOIN atlantia a2 ON a2.time = Sub1.minTime AND a1.date = a2.date
INNER JOIN atlantia a3 ON a3.time = Sub1.minTime AND a1.date = a3.date
GROUP BY a1.date , timeInterval