Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Wykrywaj kolejne elementy spełniające określone kryteria w szeregu czasowym

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?




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Dołącz do tej samej tabeli na podstawie znacznika czasu i poziomu zapasów

  2. Wypełnianie formularzy html danymi mysql przy użyciu php null

  3. Laravel i zapytania z wieloma licznikami przy użyciu Eloquent

  4. Tworzysz niestandardowe zapytanie za pomocą Spring DATA JPA?

  5. Kod błędu MySQL:1005