Mysql
 sql >> Base de données >  >> RDS >> Mysql

Détecter les éléments consécutifs répondant à des critères particuliers dans une série chronologique

Mon approche à cela :commencez par la série chronologique d'observations et attribuez à chacune un numéro de série.

Cette numérotation de série est une douleur dans le cou de MySQL, mais peu importe. Étant donné une table avec une colonne ts (un élément datetime) et une colonne temp, voici la requête pour les obtenir avec des numéros de série.

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

Jetez un oeil à ce sqlfiddle :http://sqlfiddle.com/#!2/ d81e2/5/0

OK, c'est assez banal. Maintenant, disons que nous recherchons des périodes où la température est de 25 degrés ou plus. Pour ce faire, nous devons découper la série chronologique afin qu'elle omette ces observations. Cela se passe comme ceci :

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

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

Maintenant, la prochaine astuce consiste à trouver les intervalles de temps dans cette séquence. Nous pouvons utiliser la technique de ce poste SO pour le faire. Méthode de trouver des lacunes dans les données de séries chronologiques dans MySQL ?

Prochaine étape, nous le joignons à lui-même.

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)

Cette requête obtient l'intervalle de temps entre chaque élément de la série et celui qui le suit. Conceptuellement, c'est une chose simple à faire, mais délicate dans la version MySQL de SQL. Voici la requête complète.

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)

Voici le sqlfiddle :http://sqlfiddle.com/#!2/d81e2/13 /0 Notez que certains des trous durent 30 minutes. C'est normal pour des lectures consécutives. Certains durent 60 minutes. C'est également normal, car la série chronologique que j'utilise comporte des entrées manquantes. Les entrées de cet ensemble de résultats affichent les heures et les températures immédiatement avant les écarts.

Donc, il ne reste plus qu'à se débarrasser des vides inutiles (30 et 60 minutes) puis à ordonner les vides restants par ordre décroissant.

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

Cela donne une ligne pour chaque séquence de temps où la température est supérieure à 25 degrés ; le plus long d'abord. L'élément affiché dans le jeu de résultats est la dernière fois que la température a été inférieure à 25 avant qu'elle n'augmente. Violon SQL. http://sqlfiddle.com/#!2/d81e2/14/0

Amusant, hein ?