Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Erkennen Sie aufeinanderfolgende Elemente, die bestimmte Kriterien in einer Zeitreihe erfüllen

Mein Ansatz dazu:Beginnen Sie mit den Zeitreihen der Beobachtungen und geben Sie jeder eine fortlaufende Nummer.

Diese Seriennummerierung ist in MySQL nervig, aber egal. Bei einer gegebenen Tabelle mit einer ts-Spalte (einem datetime-Element) und einer temp-Spalte ist hier die Abfrage, um sie mit Seriennummern zu erhalten.

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

Sehen Sie sich dieses sqlfiddle an:http://sqlfiddle.com/#!2/ d81e2/5/0

Okay, das ist ziemlich trivial. Nehmen wir an, wir suchen nach Zeiträumen, in denen die Temperatur 25 Grad oder mehr beträgt. Dazu müssen wir die Zeitreihen zerhacken, damit sie weggelassen werden diese Beobachtungen. Das geht so:

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

Hier ist sqlfiddle:http://sqlfiddle.com/#!2/d81e2/6 /0

Der nächste Trick besteht nun darin, die Zeitlücken in dieser Sequenz zu finden. Dazu können wir die Technik aus diesem SO-Beitrag verwenden. Methode Lücken in Zeitreihendaten in MySQL zu finden?

Im nächsten Schritt verbinden wir es mit sich selbst.

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)

Diese Abfrage ruft die Zeitlücke zwischen jedem Element in der Serie und dem darauffolgenden ab. Das ist konzeptionell einfach, aber in der MySQL-Version von SQL schwierig. Hier ist die vollständige Abfrage.

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)

Hier ist sqlfiddle:http://sqlfiddle.com/#!2/d81e2/13 /0 Beachten Sie, dass einige der Lücken 30 Minuten dauern. Das ist normal für aufeinanderfolgende Lesungen. Einige sind 60 Minuten. Das ist auch normal, weil die von mir verwendete Zeitreihe einige fehlende Einträge enthält. Die Einträge in dieser Ergebnismenge zeigen die Zeiten und Temperaturen unmittelbar vor den Lücken.

Also bleibt nur noch, die Junk-Lücken (30 und 60 Minuten) loszuwerden und dann die verbleibenden Lücken in absteigender Reihenfolge zu ordnen.

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

Dies ergibt eine Zeile für jede Zeitsequenz, in der die Temperatur über 25 Grad liegt; die längste Zeit zuerst. Das im Ergebnissatz angezeigte Element ist die letzte Temperatur unter 25, bevor sie gestiegen ist. SQL-Geige. http://sqlfiddle.com/#!2/d81e2/14/0

Spaß, nicht wahr?