检测符合时间序列中特定条件的连续项目

时间:2013-06-14 13:16:48

标签: php mysql time-series

我有一个MySQL数据库,每半小时就有超过92.000行的天气寄存器。 一天|月|年|时间|温度| ... 我试图获得(在PHP中)峰值温度:显示最大时间(连续寄存器),温度=<每月最低(温度)+3。

我将不胜感激任何帮助!

1 个答案:

答案 0 :(得分:0)

我的方法:从时间序列的观察开始,给每个人一个序列号。

这个序列号在MySQL中是一个痛苦的问题,但无论如何。给定一个带有ts列(日期时间项)和临时列的表,这里是查询以获取序列号。

SELECT @sample:=@sample+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      ORDER BY ts
    ) C,
  (SELECT @sample:=0) s 

看看这个sqlfiddle:http://sqlfiddle.com/#!2/d81e2/5/0

好的,这非常简单。现在,假设我们正在寻找温度为25度或更高的时间段。要做到这一点,我们需要删除时间序列,以便省略这些观察结果。就是这样:

SELECT @sample:=@sample+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      WHERE NOT temp >= 25
      ORDER BY ts
    ) C,
  (SELECT @sample:=0) s

这是sqlfiddle:http://sqlfiddle.com/#!2/d81e2/6/0

现在接下来的技巧是找到此序列中的时间间隔。我们可以使用这篇SO帖子中的技术来做到这一点。 Method of finding gaps in time series data in MySQL?

下一步,我们加入它自己。

SELECT two.ser, two.ts, two.temp, 
       TIMESTAMPDIFF(MINUTE, two.ts, one.ts) gap
  FROM (
     /* virtual table */
  ) ONE
  JOIN (
     /* same virtual table */
  ) TWO ON (TWO.ser+ 1 = ONE.ser)

此查询获取系列中每个项目与其后的项目之间的时间间隔。从概念上讲这是一件简单的事情,但在MySQL版本的SQL中却很棘手。这是完整的查询。

SELECT two.ser, two.ts, two.temp, 
       TIMESTAMPDIFF(MINUTE, two.ts, one.ts) gap
      FROM (
 SELECT @sample:=@sample+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      WHERE NOT temp >= 25
      ORDER BY ts
    ) C,
  (SELECT @sample:=0) s
      ) ONE
      JOIN (
SELECT @sample2:=@sample2+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      WHERE NOT temp >= 25
      ORDER BY ts
    ) C,
  (SELECT @sample2:=0) s
      ) TWO ON (TWO.ser+ 1 = ONE.ser)

这是sqlfiddle:http://sqlfiddle.com/#!2/d81e2/13/0请注意,有些间隙持续时间为30分钟。连续读数是正常的。有些是60分钟。这也很正常,因为我使用的时间序列有一些缺失的条目。此结果集中的条目显示间隙之前的时间和温度。

所以,剩下的就是摆脱垃圾间隙(30分钟和60分钟),然后按降序排列剩余的间隙。

SELECT two.ts, two.temp, 
       TIMESTAMPDIFF(MINUTE, two.ts, one.ts) gap
      FROM (
 SELECT @sample:=@sample+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      WHERE NOT temp >= 25
      ORDER BY ts
    ) C,
  (SELECT @sample:=0) s
      ) ONE
      JOIN (
SELECT @sample2:=@sample2+1 AS ser, ts, temp
  FROM (
     SELECT ts,temp
       FROM t
      WHERE NOT temp >= 25
      ORDER BY ts
    ) C,
  (SELECT @sample2:=0) s
      ) TWO ON (TWO.ser+ 1 = ONE.ser)
 WHERE TIMESTAMPDIFF(MINUTE, two.ts, one.ts)> 60
 ORDER BY TIMESTAMPDIFF(MINUTE, two.ts, one.ts) DESC

对于温度高于25度的每个时间序列,这给出一行;最长的时间。结果集中显示的项目是上次温度低于25之前的最后一次。 SQL小提琴。 http://sqlfiddle.com/#!2/d81e2/14/0

有趣,嗯?