Zde je jeden přístup.
Začněte seřazením stavových řádků podle časového razítka (vložené zobrazení s aliasem s
). Poté použijte uživatelské proměnné MySQL k uchování hodnot z předchozích řádků při zpracování každého řádku.
To, co skutečně hledáme, je stav „nahoře“, který bezprostředně následuje po sledu stavu „dolů“. A když najdeme tento řádek se stavem 'nahoře', skutečně potřebujeme nejstarší časové razítko z předchozí řady stavu 'dolů'.
Takže něco takového bude fungovat:
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
Toto funguje pro konkrétní soubor dat, který zobrazujete.
To, co toto nezpracovává (co nevrací), je období „dolů“, které ještě neskončilo, to znamená posloupnost stavu „dolů“ bez následujícího stavu „nahoru“.
Chcete-li se vyhnout operaci řazení souborů k vrácení řádků v pořadí, budete chtít krycí index na (time,status)
. Tento dotaz vygeneruje dočasnou tabulku (MyISAM), která zhmotní vložený pohled s aliasem d
.
POZNÁMKA: Abyste pochopili, co tento dotaz dělá, odloupněte tento nejvzdálenější dotaz a spusťte pouze dotaz pro vložené zobrazení s aliasem d
(můžete přidat s.time
do výběrového seznamu.)
Tento dotaz získává každý řádek se stavem „nahoru“ nebo „dolů“. "Trik" je v tom, že přiřazuje čas "začátek" i "konec" (označení období dolů) pouze řádkům, které končí období "dolů". (To znamená, že první řádek se stavem 'nahoru' po řádcích se stavem 'dolů'.) Zde se dělá skutečná práce, nejvzdálenější dotaz pouze odfiltruje všechny "nadbytečné" řádky v této sadě výsledků (že jsme nepotřebuji.)
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
Účel inline zobrazení s aliasem s
je získat řádky seřazené podle hodnoty časového razítka, abychom je mohli zpracovat postupně. Vložený pohled s aliasem i
je tam jen proto, abychom mohli inicializovat některé uživatelské proměnné na začátku dotazu.
Pokud bychom běželi na Oracle nebo SQL Server, mohli bychom využít „analytické funkce“ nebo „hodnotící funkce“ (jak se jmenují). MySQL nic takového neposkytuje, takže si musíme „vytvořit vlastní ".
."