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

SQL - Find alle nedetider og længden af ​​nedetider fra MySQL-data (sæt af rækker med tidsstempler og statusmeddelelser)

Her er én tilgang.

Start med at få statusrækkerne i rækkefølge efter tidsstempel (indbygget visning kaldet s ). Brug derefter MySQL-brugervariabler til at beholde værdierne fra tidligere rækker, mens du behandler hver række.

Det, vi virkelig leder efter, er en 'op'-status, der umiddelbart følger en sekvens af 'ned'-status. Og når vi finder den række med "op"-status, er det, vi virkelig har brug for, det tidligste tidsstempel fra den foregående serie af "ned"-status.

Så noget som dette vil virke:

SELECT d.start_down
     , d.ended_down
  FROM (SELECT @i := @i + 1 AS i
             , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
             , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
             , @status := s.status
         FROM (SELECT t.time
                    , t.status
                 FROM mydata t
                WHERE t.status IN ('up','down')
                ORDER BY t.time ASC, t.status ASC
              ) s
         JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i
      ) d
WHERE d.start_down IS NOT NULL
  AND d.ended_down IS NOT NULL

Dette virker for det bestemte datasæt, du viser.

Hvad dette ikke håndterer (hvad det ikke returnerer) er en 'ned'-periode, der endnu ikke er afsluttet, det vil sige en sekvens af 'ned'-status uden følgende 'op'-status.

For at undgå en filsorteringsoperation for at returnere rækkerne i rækkefølge, vil du have et dækkende indeks på (time,status) . Denne forespørgsel vil generere en midlertidig (MyISAM) tabel for at materialisere den indbyggede visning kaldet d .

BEMÆRK: For at forstå, hvad denne forespørgsel gør, skal du fjerne den yderste forespørgsel og kun køre forespørgslen for den indbyggede visning kaldet d (du kan tilføje s.time til den valgte liste.)

Denne forespørgsel får hver række med statussen "op" eller "ned". "Tricket" er, at det kun tildeler både et "start"- og "slut"-tidspunkt (markerer en ned-periode) på de rækker, der slutter en "ned"-periode. (Det vil sige, den første række med en 'op'-status følger rækker med en 'ned'-status.) Det er her det rigtige arbejde udføres, den yderste forespørgsel filtrerer bare alle de "ekstra" rækker fra i dette resultatsæt (som vi behøver ikke.)

SELECT @i := @i + 1 AS i
     , @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
     , @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
     , @status := s.status
     , s.time
  FROM (SELECT t.time
             , t.status
          FROM mydata t
         WHERE t.status IN ('up','down')
         ORDER BY t.time ASC, t.status ASC
       ) s
  JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i

Formålet med inline-visning kaldet s er at få rækkerne ordnet efter tidsstempelværdi, så vi kan behandle dem i rækkefølge. Den indbyggede visning kaldet i er der bare, så vi kan initialisere nogle brugervariable i starten af ​​forespørgslen.

Hvis vi kørte på Oracle eller SQL Server, kunne vi gøre brug af henholdsvis "analytiske funktioner" eller "rangeringsfunktioner" (som de hedder.) MySQL giver ikke noget lignende, så vi skal "rulle vores egne" ".



  1. Gennemfør Laravel 8 Soft Slet &Gendan slettede optegnelser Tutorial

  2. Hvordan tæller man antallet af forekomster af en bestemt understreng i en SQL-varchar?

  3. Sådan formulerer du din værdi som DBA til finansdirektører

  4. Er der nogen fordel ved at oprette og indeksere en primærnøgle?