我的方法是:从观察的时间序列开始,给每个观察一个序列号。
这个序列号在 MySQL 中是一件令人头疼的事情,但没关系。给定一个包含 ts 列(日期时间项)和 temp 列的表,下面是使用序列号获取它们的查询。
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 post 中的技术来做到这一点。 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
有趣,嗯?