Moje podejście do tego:zacznij od szeregów czasowych obserwacji i nadaj każdej z nich numer seryjny.
Ta numeracja seryjna jest w MySQL uciążliwa, ale nieważne. Biorąc pod uwagę tabelę z kolumną ts (pozycja datetime) i kolumną temp, oto zapytanie, aby uzyskać je z numerami seryjnymi.
SELECT @sample:[email protected]+1 AS ser, ts, temp
FROM (
SELECT ts,temp
FROM t
ORDER BY ts
) C,
(SELECT @sample:=0) s
Spójrz na ten sqlfiddle:http://sqlfiddle.com/#!2/ d81e2/5/0
OK, to dość trywialne. Załóżmy teraz, że szukamy okresów, w których temperatura wynosi 25 stopni lub więcej. Aby to zrobić, musimy podzielić szereg czasowy, aby pominął te obserwacje. To wygląda tak:
SELECT @sample:[email protected]+1 AS ser, ts, temp
FROM (
SELECT ts,temp
FROM t
WHERE NOT temp >= 25
ORDER BY ts
) C,
(SELECT @sample:=0) s
Oto sqlfiddle:http://sqlfiddle.com/#!2/d81e2/6 /0
Teraz kolejna sztuczka polega na znalezieniu przerw czasowych w tej sekwencji. W tym celu możemy użyć techniki z tego posta SO. Metoda wyszukiwania luk w danych szeregów czasowych w MySQL?
W następnym kroku łączymy go ze sobą.
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)
To zapytanie pobiera odstęp czasowy między każdym elementem w serii a kolejnym. Jest to prosta rzecz do wykonania koncepcyjnie, ale trudna w wersji SQL MySQL. Oto pełne zapytanie.
SELECT two.ser, two.ts, two.temp,
TIMESTAMPDIFF(MINUTE, two.ts, one.ts) gap
FROM (
SELECT @sample:[email protected]+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:[email protected]+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)
Oto sqlfiddle:http://sqlfiddle.com/#!2/d81e2/13 /0 Zauważ, że niektóre przerwy trwają 30 minut. To normalne w przypadku kolejnych odczytów. Niektóre trwają 60 minut. To też normalne, ponieważ w szeregu czasowym, którego używam, brakuje niektórych wpisów. Wpisy w tym zestawie wyników pokazują czasy i temperatury bezpośrednio przed przerwami.
Pozostało więc tylko pozbyć się luk śmieciowych (30 i 60 minut), a następnie uporządkować pozostałe luki w kolejności malejącej.
SELECT two.ts, two.temp,
TIMESTAMPDIFF(MINUTE, two.ts, one.ts) gap
FROM (
SELECT @sample:[email protected]+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:[email protected]+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
Daje to jeden wiersz dla każdej sekwencji czasu, w której temperatura przekracza 25 stopni; najpierw najdłużej. Pozycja pokazana w zestawie wyników to ostatnia temperatura poniżej 25, zanim wzrosła. Skrzypce SQL. http://sqlfiddle.com/#!2/d81e2/14/0
Zabawne, co?