Ето един подход.
Започнете, като подредите редовете за състоянието по времева марка (вграден изглед с псевдоним като s
). След това използвайте потребителски променливи на MySQL, за да запазите стойностите от предишните редове, докато обработвате всеки ред.
Това, което наистина търсим, е статус „нагоре“, който непосредствено следва последователност от статус „надолу“. И когато намерим този ред със статус „нагоре“, това, от което наистина се нуждаем, е най-ранната времева марка от предходната серия от статус „надолу“.
Така че, нещо подобно ще работи:
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
Това работи за конкретния набор от данни, който показвате.
Това, което това не обработва (това, което не връща), е период „надолу“, който все още не е приключил, тоест поредица от състояние „надолу“ без последващо състояние „нагоре“.
За да избегнете операция за сортиране на файлове за връщане на редовете в ред, ще искате покриващ индекс на (time,status)
. Тази заявка ще генерира временна (MyISAM) таблица, за да материализира вградения изглед с псевдоним като d
.
ЗАБЕЛЕЖКА: За да разберете какво прави тази заявка, отлепете тази най-външна заявка и изпълнете само заявката за вградения изглед с псевдоним като d
(можете да добавите s.time
към списъка за избор.)
Тази заявка получава всеки ред със състояние "нагоре" или "надолу". "Трикът" е, че присвоява както "начало", така и "край" (маркиране на период на спад) само на редовете, които завършват "надолу" период. (Тоест, първият ред със състояние „нагоре“ следва редове със състояние „надолу“.) Тук се извършва истинската работа, най-външната заявка просто филтрира всички „допълнителни“ редове в този набор от резултати (че ние няма нужда.)
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
Целта на вградения изглед с псевдоним като s
е да получим редовете, подредени по стойност на времеви печат, така че да можем да ги обработваме последователно. Вграденият изглед с псевдоним като i
е само там, за да можем да инициализираме някои потребителски променливи в началото на заявката.
Ако работихме на Oracle или SQL Server, бихме могли да използваме "аналитични функции" или "функции за класиране" (както се наричат съответно.) MySQL не предоставя нищо подобно, така че трябва да "развием нашите собствени ".