これは、適切にソートされた行セットでUNIXタイムスタンプ変換と変数割り当てを使用して実行できます。「適切にソートされた」とは、行を、、server
次に。でソートする必要があることを意味しますtime
。変数を使用して、テーブル内のすべての行の前のイベントからのオンライン時間(間隔)を秒単位で取得する方法は次のとおりです(server_status
この回答の目的で呼び出されます)。
SELECT
*,
@currenttime := UNIX_TIMESTAMP(`time`),
@lasttime := CASE
WHEN server <> @lastserver OR @laststatus = 'offline'
THEN @currenttime
ELSE @lasttime
END,
@currenttime - @lasttime AS seconds_online,
@lasttime := @currenttime,
@lastserver := server,
@laststatus := status
FROM
server_satus s,
(SELECT @lastserver := 0) x
ORDER BY
s.server,
s.`time`
ご覧のとおり、一時変数(@currenttime
)はUNIXタイムスタンプと同等の値で初期化されますtime
。別の変数は前のタイムスタンプを保持するために使用され、2つの間の差を計算できます。他の変数は、前のサーバーIDと前のステータスを記憶するために使用されるため、必要に応じて、差は0として返されます(これは、サーバーの最初のイベントとイベントの後に続く行を記録するすべての行に対して行われoffline
ます)。
これで、上記のクエリによって生成された結果セットをグループ化し、値をSUM()し、seconds_online
それらを60で割って、次のように分を取得できます(秒に満足できない場合)。
SELECT
server,
SUM(seconds_online) DIV 60 AS minutes
FROM (
the query above
) s
ただし、最初のクエリは、それぞれの最後のイベント以降にオンラインで費やされたサーバーの秒数を実際には計算しないことに注意してください。つまり、現在の時刻は最新のイベントレコードの時刻とは大きく異なる可能性があり、クエリは前の行からの行ごとの秒数を計算するため、考慮されません。
これを解決する1つの方法は、現在のタイムスタンプと最後のレコードと同じステータスを含むサーバーごとに1つの行を追加することです。したがって、server_status
ソーステーブルとして、次のものを使用するだけでなく、次のようになります。
SELECT
server,
`time`,
status
FROM server_status
UNION ALL
SELECT
s.server,
NOW() AS `time`,
s.status
FROM server_status s
INNER JOIN (
SELECT
server,
MAX(`time`) AS last_time
FROM server_status
GROUP BY
server
) t
ON s.server = t.server AND s.`time` = t.last_time
UNION ALLの左側は、からすべての行を返すだけserver_status
です。右側の部分は、最初にtime
サーバーごとに最後のものを取得し、次に結果セットに参加してserver_status
、対応するステータスを取得し、途中で置き換えtime
ますNOW()
。
これで、現在の時刻を反映する「偽の」イベント行がテーブルに完成したので、最初のクエリで使用した方法を適用できます。最終的なクエリは次のようになります。
SELECT
server,
SUM(seconds_online) DIV 60 AS minutes_online
FROM (
SELECT
*,
@currenttime := UNIX_TIMESTAMP(`time`),
@lasttime := CASE
WHEN server <> @lastserver OR @laststatus = 'offline'
THEN @currenttime
ELSE @lasttime
END,
@currenttime - @lasttime AS seconds_online,
@lasttime := @currenttime,
@lastserver := server,
@laststatus := status
FROM
(
SELECT
server,
`time`,
status
FROM server_status
UNION ALL
SELECT
s.server,
NOW() AS `time`,
s.status
FROM server_status s
INNER JOIN (
SELECT
server,
MAX(`time`) AS last_time
FROM server_status
GROUP BY
server
) t
ON s.server = t.server AND s.`time` = t.last_time
) s,
(SELECT @lastserver := 0) x
ORDER BY
s.server,
s.`time`
) s
GROUP BY
server
;
また、SQL Fiddleでも試してみることができます(試してみることができます)。