sql >> Database >  >> RDS >> Mysql

SQL - Vind alle uitvaltijden en de lengte van de uitvaltijden uit MySQL-gegevens (reeks rijen met tijdstempels en statusberichten)

Hier is één benadering.

Begin met het sorteren van de statusrijen op tijdstempel (inline-weergave gealiast als s ). Gebruik vervolgens MySQL-gebruikersvariabelen om de waarden van vorige rijen te behouden, terwijl u door elke rij gaat.

Waar we echt naar op zoek zijn, is een 'omhoog'-status die onmiddellijk volgt op een reeks 'omlaag'-statussen. En als we die rij met de 'omhoog'-status vinden, hebben we echt de vroegste tijdstempel van de voorgaande reeks van de 'omlaag'-status nodig.

Dus zoiets als dit zal werken:

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

Dit werkt voor de specifieke dataset die je laat zien.

Wat dit niet afhandelt (wat het niet teruggeeft) is een 'down'-periode die nog niet is afgelopen, dat wil zeggen een reeks van 'down'-status zonder vervolg'-up'-status.

Om een ​​bestandssorteerbewerking te vermijden om de rijen op volgorde te retourneren, wilt u een dekkende index op (time,status) . Deze query genereert een tijdelijke (MyISAM)-tabel om de inline-weergave onder de alias d te realiseren .

OPMERKING: Om te begrijpen wat deze query doet, verwijdert u die buitenste query en voert u alleen de query uit voor de inline-weergave met de alias d (je kunt s.time toevoegen naar de selectielijst.)

Deze query krijgt elke rij met een 'omhoog' of 'omlaag' status. De "truc" is dat het zowel een "start"- als een "eind"-tijd toewijst (een down-periode markeren) aan alleen de rijen die een down-periode beëindigen. (Dat wil zeggen, de eerste rij met een 'omhoog'-status die volgt op rijen met een 'omlaag'-status.) Hier wordt het echte werk gedaan, de buitenste query filtert gewoon alle "extra" rijen in deze resultatenset (die we niet nodig.)

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

Het doel van de inline-weergave met een alias als s is om de rijen te ordenen op tijdstempelwaarde, zodat we ze in volgorde kunnen verwerken. De inline-weergave met een alias als i is er gewoon, zodat we enkele gebruikersvariabelen aan het begin van de zoekopdracht kunnen initialiseren.

Als we op Oracle of SQL Server zouden draaien, zouden we gebruik kunnen maken van "analytische functies" of "rangschikkingsfuncties" (zoals ze respectievelijk worden genoemd). MySQL biedt zoiets niet, dus we moeten "onze eigen ".



  1. Lat Lng-waarden opslaan in MySQL met behulp van Spatial Point Type

  2. Wat is de beste manier om datums te beheren in PHP, MySQL, enz.?

  3. PostgreSQL-query om per dag te tellen/groeperen en dagen zonder gegevens weer te geven

  4. MySQL Socket weigert verbinding na duizenden opeenvolgende verbindingen