sql >> Databasteknik >  >> RDS >> Mysql

SQL - Hitta alla stilleståndstider och längden på stilleståndstiderna från MySQL-data (uppsättning rader med tidsstämplar och statusmeddelanden)

Här är ett tillvägagångssätt.

Börja med att få statusraderna i ordning efter tidsstämpel (inlinevy alias som s ). Använd sedan MySQL-användarvariabler för att behålla värdena från tidigare rader när du bearbetar varje rad.

Det vi verkligen letar efter är en "upp"-status som omedelbart följer en sekvens av "ner"-status. Och när vi hittar den raden med "upp"-status, behöver vi verkligen den tidigaste tidsstämpeln från den föregående serien med "ner"-status.

Så något sånt här kommer att fungera:

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

Detta fungerar för den specifika datamängden du visar.

Vad det här inte hanterar (vad det inte returnerar) är en "ner"-period som ännu inte är avslutad, det vill säga en sekvens av "ner"-status utan efterföljande "upp"-status.

För att undvika en filsorteringsoperation för att returnera raderna i ordning, vill du ha ett täckande index på (time,status) . Denna fråga kommer att generera en temporär (MyISAM) tabell för att materialisera inlinevyn alias som d .

OBS: För att förstå vad den här frågan gör, dra bort den yttersta frågan och kör bara frågan för inlinevyn med alias som d (du kan lägga till s.time till den valda listan.)

Den här frågan får varje rad med statusen "upp" eller "ner". "Knepet" är att det tilldelar både en "start" och "slut" tid (markerar en ned period) på endast de rader som avslutar en "ner" period. (Det vill säga den första raden med statusen "upp" följer efter rader med statusen "ner".) Det är här det verkliga arbetet görs, den yttersta frågan filtrerar bara bort alla "extra" rader i denna resultatuppsättning (som vi behöver inte.)

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

Syftet med inlinevy alias som s är att få raderna ordnade efter tidsstämpelvärde, så att vi kan bearbeta dem i sekvens. Den infogade vyn med alias som i finns bara där så att vi kan initiera några användarvariabler i början av frågan.

Om vi ​​körde på Oracle eller SQL Server skulle vi kunna använda oss av "analytiska funktioner" eller "rankningsfunktioner" (som de heter, respektive.) MySQL ger inget sådant, så vi måste "rulla våra egna ".



  1. Enkel men tung applikation som kräver mycket resurser. Hur optimerar man?

  2. Vilket är det bästa PostgreSQL High Availability Framework? PAF vs. repmgr vs. Patroni Infographic

  3. Hur ersätter man icke-numeriska tecken i MySQL?

  4. Generated Value i Postgres