SQL查询来计算应用程序的正常运行时间

时间:2015-09-28 14:29:29

标签: sql sql-server sql-server-2008

我有一个应用程序可以在同一个表中记录连接和断开连接等信息。我想尝试计算总的应用程序正常运行时间。

表结构是这样的

status     time 
connect    2015-09-28 12:05:45.783
disconnect 2015-09-28 12:09:45.783
connect    2015-09-28 12:35:15.783
disconnect 2015-09-28 14:45:35.783

编辑:

如何编写查询来计算?我试图使用总时间,有点像这样

/*
status     time 
connect    2015-09-28 12:05:45.783
disconnect 2015-09-28 12:09:45.783
connect    2015-09-28 12:35:15.783
disconnect 2015-09-28 14:45:35.783
*/
declare @0 datetime;
set @0 = '2015-09-28 12:00:0.000'

declare @1 datetime;
set @1 = '2015-09-28 12:05:45.783'

declare @2 datetime;
set @2 =  '2015-09-28 12:09:45.783'

declare @3 datetime;
set @3 =  '2015-09-28 12:35:45.783'

declare @4 datetime;
set @4 = '2015-09-28 14:45:45.783'

select DATEDIFF(MS, @1, @3)
select DATEDIFF(MS, @2, @4)

3 个答案:

答案 0 :(得分:3)

使用公用表表达式,您可以将状态历史记录安排到包含每条记录的开始时间和结束时间的视图中,如下所示:http://sqlfiddle.com/#!3/18438/1

with t1 (stat, ts, ndx) as (
  select stat, ts, row_number() over(order by ts)
  from connected
)
,
t2 (stat, startts, endts) as (
  select t1.stat, t1.ts, coalesce(t2.ts, getdate())
  from t1
  left join t1 t2
  on t2.ndx = t1.ndx + 1
)
select * from t2
order by startts

我使用coalesce(t2.ts, getdate())来获取您范围内最后一条记录的当前日期时间。

如果您想查找每个状态的持续时间,请使用datediff()功能,如下所示:http://sqlfiddle.com/#!3/18438/2

with t1 (stat, ts, ndx) as (
  select stat, ts, row_number() over(order by ts)
  from connected
)
,
t2 (stat, startts, endts) as (
  select t1.stat, t1.ts, coalesce(t2.ts, getdate())
  from t1
  left join t1 t2
  on t2.ndx = t1.ndx + 1
)
select stat, startts, endts, datediff(second, startts, endts) as elapsed
from t2
order by startts

如果你想要总的上下时间,那就是数学和格式:http://sqlfiddle.com/#!3/e90a3/33

with t1 (stat, ts, ndx) as (
  select stat, ts, row_number() over(order by ts)
  from connected
)
,
t2 (stat, startts, endts) as (
  select t1.stat, t1.ts, coalesce(t2.ts, getdate())
  from t1
  left join t1 t2
  on t2.ndx = t1.ndx + 1
)
,
t3 (stat, totaltime) as (
  select stat, sum(datediff(second, startts, endts))
  from t2
  group by stat
)
select stat,
  cast(totaltime / 86400 as varchar) + ' ' + 
  right('0' + cast((totaltime % 86400) / 3600 as varchar),2) + ':' +
  right('0' + cast((totaltime % 3600) / 60 as varchar),2)  + ':' +
  right('0' + cast(totaltime % 60 as varchar),2)
  as [Days HH:MM:SS]
from t3

答案 1 :(得分:1)

这个问题似乎被抛弃了。然而,为了帮助未来有类似问题的读者,以下是如何处理它:

该表包含交替记录:连接,断开连接,连接,断开等。我们可以使用LAG查看上一行。这样做,我们只需要将断开记录与之前的记录一起取出。时间,这当然是他们的连接时间。

唯一重要的是,首先获取前一次然后过滤掉'断开'。如果我们直接使用WHERE status = 'disconnect进行过滤,那么LAG会给我们之前的 disconnect 记录的时间。因此,我们首先编写内部滞后查询,然后使用它来过滤外部所需的记录。

select sum(time_used) as total_seconds
from
(
  select 
    datediff(second, log_time, lag(log_time) over (order by log_time)) as time_used,
    status
  from connection_logs
) times_used
where status = 'disconnect';

SQL小提琴:http://www.sqlfiddle.com/#!3/dfba6a/1

我们通常也应该考虑缺少连接或断开记录的情况,因此我们有两个连续的连接或断开连接。一种解决方案是忽略失踪合作伙伴的记录,因此我们要查看lag(status),只有在状态确实是“连接”时才使用它:

select sum(time_used) as total_seconds
from
(
  select 
    datediff(second, log_time, lag(log_time) over (order by log_time)) as time_used,
    status,
    lag(status) over (order by log_time) as previous_status
  from connection_logs
) times_used
where status = 'disconnect'
and previous_status = 'connect';

SQL小提琴http://www.sqlfiddle.com/#!3/dfba6a/2

答案 2 :(得分:0)

这很快且很脏但是它有效 - 使用公用表表达式(cte):

;WITH cte
AS
(SELECT t.statustext, logtime, ROW_NUMBER() OVER(PARTITION BY statustext ORDER BY logtime) AS id
FROM    dbo.NameOfYourTable t
)

SELECT  con.logtime AS LoginTime, 
        discon.logtime AS LogoutTime, 
        DATEDIFF(MINUTE,con.logtime,discon.logtime) AS SessionTimeInMinutes
FROM    cte AS con
        INNER JOIN cte AS discon ON con.id = discon.id
WHERE   con.statustext = 'connect'
        AND discon.statustext = 'disconnect'

注意:对于我的示例,我将列名更改为statustext和logtime。 statustime是SQL关键字,不应用作列名!