Mysql
 sql >> Database >  >> RDS >> Mysql

Rileva elementi consecutivi che soddisfano criteri particolari in una serie temporale

Il mio approccio a questo:iniziare con le serie temporali delle osservazioni e assegnare a ciascuna un numero di serie.

Questa numerazione di serie è un dolore al collo in MySQL, ma non importa. Data una tabella con una colonna ts (un elemento datetime) e una colonna temporanea, ecco la query per ottenerle con i numeri di serie.

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

Dai un'occhiata a questo sqlfiddle:http://sqlfiddle.com/#!2/ d81e2/5/0

OK, è abbastanza banale. Ora, diciamo che stiamo cercando periodi di tempo in cui la temperatura è di 25 gradi o superiore. Per fare ciò, dobbiamo tagliare la serie temporale in modo che ometta quelle osservazioni. Funziona così:

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

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

Ora il prossimo trucco è trovare gli intervalli di tempo in questa sequenza. Possiamo usare la tecnica di questo post SO per farlo. Metodo di trovare lacune nei dati delle serie temporali in MySQL?

Il prossimo passo, lo uniamo a se stesso.

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)

Questa query ottiene l'intervallo di tempo tra ciascun elemento della serie e quello successivo. È una cosa semplice da fare concettualmente, ma complicata nella versione MySQL di SQL. Ecco la domanda completa.

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)

Ecco sqlfiddle:http://sqlfiddle.com/#!2/d81e2/13 /0 Si noti che alcuni degli intervalli durano 30 minuti. È normale per letture consecutive. Alcuni sono 60 minuti. Anche questo è normale, perché la serie temporale che sto usando ha alcune voci mancanti. Le voci in questo set di risultati mostrano i tempi e le temperature immediatamente prima degli intervalli.

Quindi, non resta che sbarazzarsi dei gap spazzatura (30 e 60 minuti) e quindi ordinare i gap rimanenti in ordine decrescente.

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

Questo dà una riga per ogni sequenza di tempo in cui la temperatura è superiore a 25 gradi; prima il tempo più lungo. L'elemento mostrato nel set di risultati è l'ultima volta che la temperatura è stata inferiore a 25 prima che aumentasse. SQL Violino. http://sqlfiddle.com/#!2/d81e2/14/0

Divertente, eh?