sql >> Database >  >> RDS >> Mysql

Methode om hiaten in tijdreeksgegevens in MySQL te vinden?

Laten we om te beginnen het aantal inschrijvingen per uur samenvatten in uw tabel.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
       COUNT(*) samplecount
  FROM table
 GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)

Als u nu elke zes minuten (tien keer per uur) iets logt, zouden al uw samplecount-waarden tien moeten zijn. Deze uitdrukking:CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) ziet er harig uit, maar het kapt je tijdstempels eenvoudig af tot het uur waarin ze voorkomen door de minuut en seconde op nul te zetten.

Dit is redelijk efficiënt en helpt u op weg. Het is erg efficiënt als u een index op uw entry_time-kolom kunt plaatsen en uw zoekopdracht kunt beperken tot, laten we zeggen, voorbeelden van gisteren, zoals hier weergegeven.

SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
       COUNT(*) samplecount
  FROM table
 WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY
   AND entry_time < CURRENT_DATE
 GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)

Maar het is niet zo goed in het detecteren van hele uren die verstrijken met ontbrekende monsters. Het is ook een beetje gevoelig voor jitter in uw bemonstering. Dat wil zeggen, als uw steekproef op het hoogste uur soms een halve seconde te vroeg is (10:59:30) en soms een halve seconde te laat (11:00:30), zijn uw uuroverzichten uitgeschakeld. Dus dit uuroverzicht (of dagoverzicht, of minutenoverzicht, enz.) is niet kogelvrij.

Je hebt een self-join-query nodig om dingen helemaal goed te krijgen; het is een beetje meer een haarbal en lang niet zo efficiënt.

Laten we beginnen met het maken van een virtuele tabel (subquery) zoals deze voor onszelf met genummerde voorbeelden. (Dit is lastig in MySQL; sommige andere dure DBMS'en maken het gemakkelijker. Maakt niet uit.)

  SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
    FROM (
        SELECT entry_time, value
      FROM table
         ORDER BY entry_time
    ) C,
    (SELECT @sample:=0) s

Deze kleine virtuele tabel geeft entry_num, entry_time, waarde.

De volgende stap voegen we toe aan zichzelf.

SELECT one.entry_num, one.entry_time, one.value, 
       TIMEDIFF(two.value, one.value) interval
  FROM (
     /* virtual table */
  ) ONE
  JOIN (
     /* same virtual table */
  ) TWO ON (TWO.entry_num - 1 = ONE.entry_num)

Dit plaatst de tabellen naast elkaar, verschoven door een enkele invoer, geregeld door de ON-clausule van de JOIN.

Tenslotte kiezen we de waarden uit deze tabel met een interval groter is dan uw drempel, en er zijn de tijden van de monsters vlak voor de ontbrekende.

De algemene zelf-join-query is dit. Ik zei toch dat het een haarbal was.

SELECT one.entry_num, one.entry_time, one.value, 
       TIMEDIFF(two.value, one.value) interval
  FROM (
    SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
      FROM (
          SELECT entry_time, value
            FROM table
           ORDER BY entry_time
      ) C,
      (SELECT @sample:=0) s
  ) ONE
  JOIN (
    SELECT @sample2:[email protected]+1 AS entry_num, c.entry_time, c.value
      FROM (
          SELECT entry_time, value
            FROM table
           ORDER BY entry_time
      ) C,
      (SELECT @sample2:=0) s
  ) TWO ON (TWO.entry_num - 1 = ONE.entry_num)

Als u dit in productie op een grote tafel moet doen, wilt u dit misschien doen voor een subset van uw gegevens. U kunt dit bijvoorbeeld elke dag doen voor de monsters van de afgelopen twee dagen. Dit zou behoorlijk efficiënt zijn, en zou er ook voor zorgen dat je om middernacht geen ontbrekende monsters over het hoofd zag. Om dit te doen zouden uw kleine rijgenummerde virtuele tafels er als volgt uitzien.

  SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
    FROM (
        SELECT entry_time, value
      FROM table
         ORDER BY entry_time
         WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY
           AND entry_time < CURRENT_DATE /*yesterday but not today*/
    ) C,
    (SELECT @sample:=0) s


  1. Oracle PL/SQL:DML-pakket online maken

  2. Hoe u de eerste rij per groep kunt krijgen in PostgreSQL

  3. Hoe MAKEDATE() werkt in MariaDB

  4. De database-e-mailwachtrij stoppen/starten in SQL Server (T-SQL)