这可以通过对正确排序的行集使用 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
,另一个用于保存前一个时间戳,以便计算两者之间的差异。其他变量用于记住先前的服务器 ID 和先前的状态,以便在必要时将差值返回为 0(对记录服务器第一个事件以及事件之后发生的事件的每一行都执行此操作offline
)。
您现在可以将上述查询生成的结果集、SUM()seconds_online
值分组并将它们除以 60 以获得分钟(如果您对秒数不满意),如下所示:
SELECT
server,
SUM(seconds_online) DIV 60 AS minutes
FROM (
the query above
) s
但是请注意,第一个查询并没有真正计算服务器自上次事件以来在线花费的秒数。也就是说,当前时间很可能与任何最新事件记录中的时间不同,并且不会被考虑在内,因为查询会计算自上一行以来每行的秒数。
解决此问题的一种方法是为每个服务器添加一行,其中包含当前时间戳和与上一条记录中相同的状态。因此,您不仅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上尝试(以及玩弄它)。