Aqui está uma abordagem.
Comece colocando as linhas de status em ordem por carimbo de data/hora (visualização em linha alias como
s
). Em seguida, use as variáveis de usuário do MySQL para manter os valores das linhas anteriores, conforme você processa cada linha. O que estamos realmente procurando é um status 'up' que segue imediatamente uma sequência de status 'down'. E quando encontramos essa linha com o status 'up', o que realmente precisamos é o carimbo de data/hora mais antigo da série anterior de status 'down'.
Então, algo assim funcionará:
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
Isso funciona para o conjunto de dados específico que você mostra.
O que isso não trata (o que não retorna) é um período 'down' que ainda não terminou, ou seja, uma sequência de status 'down' sem status 'up' seguinte.
Para evitar que uma operação de classificação de arquivos retorne as linhas em ordem, você desejará um índice de cobertura em
(time,status)
. Esta consulta irá gerar uma tabela temporária (MyISAM) para materializar a visualização em linha alias como d
. OBSERVAÇÃO: Para entender o que essa consulta está fazendo, retire essa consulta externa e execute apenas a consulta para a visualização em linha com o alias
d
(você pode adicionar s.time
para a lista de seleção.) Esta consulta está obtendo todas as linhas com um status 'up' ou 'down'. O "truque" é que ele está atribuindo um tempo de "início" e "fim" (marcando um período inativo) apenas nas linhas que terminam um período 'inativo'. (Ou seja, a primeira linha com um status 'up' seguindo as linhas com um status 'down'.) É aqui que o trabalho real é feito, a consulta mais externa apenas filtra todas as linhas "extras" neste conjunto de resultados (que nós não precisa.)
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
A finalidade da visualização em linha com alias de
s
é obter as linhas ordenadas por valor de carimbo de data/hora, para que possamos processá-las em sequência. A visualização em linha alias como i
está lá para que possamos inicializar algumas variáveis de usuário no início da consulta. Se estivéssemos rodando em Oracle ou SQL Server, poderíamos fazer uso de "funções analíticas" ou "funções de classificação" (como são chamadas, respectivamente). ".