これが1つのアプローチです。
タイムスタンプ順にステータス行を取得することから始めます (インライン ビューは としてエイリアス化されますs
)。次に、MySQL ユーザー変数を使用して、前の行の値を保持し、各行を処理します。
私たちが本当に探しているのは、一連の「ダウン」ステータスの直後に続く「アップ」ステータスです。そして、「up」ステータスの行が見つかった場合、本当に必要なのは、前の一連の「down」ステータスからの最も古いタイムスタンプです。
したがって、次のようなものが機能します。
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 で実行している場合は、"分析関数" または "ランキング関数" (それぞれ名前が付けられているとおり) を利用できます。 "。