これが1つのアプローチです。
タイムスタンプ順にステータス行を取得することから始めます(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)
にカバーインデックスが必要です。 。このクエリは、d
としてエイリアスされたインラインビューを具体化するための一時的な(MyISAM)テーブルを生成します 。
注: このクエリが何をしているのかを理解するには、その最も外側のクエリをはがし、d
としてエイリアスされたインラインビューのクエリだけを実行します。 (s.time
を追加できます 選択リストに移動します。)
このクエリは、「up」または「down」ステータスのすべての行を取得しています。 「トリック」とは、「ダウン」期間を終了する行にのみ「開始」時間と「終了」時間(ダウン期間をマーク)の両方を割り当てることです。 (つまり、「ダウン」ステータスの行に続く「アップ」ステータスの最初の行。)これが実際の作業が行われる場所であり、最も外側のクエリは、この結果セットのすべての「余分な」行を除外します(必要ありません。)
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またはSQLServerで実行している場合は、「分析関数」または「ランク付け関数」を使用できます(それぞれ名前が付けられています)。MySQLはそのようなものを提供しないため、「独自の関数をロールする必要があります。 "。