sql >> Databasteknik >  >> RDS >> Mysql

Upptäck på varandra följande objekt som uppfyller särskilda kriterier i en tidsserie

Min inställning till detta:börja med tidsserien av observationer och ge var och en ett serienummer.

Denna serienumrering är en smärta i nacken i MySQL, men det spelar ingen roll. Med tanke på en tabell med en ts-kolumn (en datetime-objekt) och en temp-kolumn, här är frågan för att få dem med serienummer.

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

Ta en titt på denna sqlfiddle:http://sqlfiddle.com/#!2/ d81e2/5/0

Okej, det är ganska trivialt. Låt oss nu säga att vi letar efter perioder där temperaturen är 25 grader eller över. För att göra detta måste vi skära upp tidsserien så att den utelämnas dessa observationer. Det går så här:

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

Här är sqlfiddle:http://sqlfiddle.com/#!2/d81e2/6 /0

Nu är nästa knep att hitta tidsluckor i denna sekvens. Vi kan använda tekniken från detta SO-inlägg för att göra det. Metod för att hitta luckor i tidsseriedata i MySQL?

Nästa steg, vi förenar det med sig självt.

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)

Den här frågan får tidsskillnaden mellan varje objekt i serien och det efter det. Det är en enkel sak att göra konceptuellt, men knepigt i MySQL-versionen av SQL. Här är hela frågan.

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)

Här är sqlfiddle:http://sqlfiddle.com/#!2/d81e2/13 /0 Observera att några av luckorna är 30 minuter långa. Det är normalt för på varandra följande avläsningar. Vissa är 60 minuter. Det är också normalt, eftersom tidsserien jag använder saknar några poster. Posterna i denna resultatuppsättning visar tiderna och temperaturerna omedelbart före luckorna.

Så, allt som återstår är att bli av med skräpluckor (30 och 60 minuter) och sedan beställa de återstående luckorna i fallande ordning.

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

Detta ger en rad för varje tidssekvens där temperaturen är över 25 grader; den längsta tiden först. Posten som visas i resultatuppsättningen är den senaste tidstemperaturen under 25 innan den gick upp. SQL fiol. http://sqlfiddle.com/#!2/d81e2/14/0

Kul, va?




  1. Hur man använder Kör omedelbart med INTO-klausul i Oracle Database

  2. Skriptet för MySQL-replikeringshälsokontroll

  3. Använder du .aggregate() på ett värde som introducerats med .extra(select={...}) i en Django-fråga?

  4. Hur får man min max och avg från tabellen i mysql med olika rader?