查询以计算连续事件之间的平均时间

时间:2009-12-22 15:03:39

标签: sql average

我的问题是如何编写SQL查询来计算连续事件之间的平均时间。

我有一张小桌子:

event Name    |    Time

stage 1       |    10:01
stage 2       |    10:03
stage 3       |    10:06
stage 1       |    10:10
stage 2       |    10:15
stage 3       |    10:21
stage 1       |    10:22
stage 2       |    10:23
stage 3       |    10:29

我想构建一个查询,以获得阶段(i)和阶段(i + 1)之间平均时间的答案。

例如, 阶段2和阶段3之间的平均时间是5:

(3+6+6)/3 =  5

8 个答案:

答案 0 :(得分:13)

答案 1 :(得分:2)

Select Avg(differ) from (
 Select s1.r, s2.r, s2.time - s1.time as differ from (
 Select * From (Select rownum as r, inn.time from table inn order by time) s1
 Join (Select rownum as r, inn.time from table inn order by time) s2
 On mod(s2.r, 3) = 2 and s2.r = s1.r + 1
 Where mod(s1.r, 3) = 1)
);

可以随着阶段数量的变化更改参数。目前,这是为了找到3阶段过程中第1阶段和第2阶段之间的平均值。

编辑一些错别字

答案 2 :(得分:1)

你的桌面设计存在缺陷。你能告诉哪个阶段1与哪个阶段2相关?如果没有办法,我认为你的查询是不可能的。

答案 3 :(得分:1)

最简单的方法是按时间排序并使用游标(tsql)迭代数据。由于游标是邪恶的,因此建议将按时间排序的数据提取到应用程序代码中并在那里进行迭代。可能还有其他方法可以在SQL中执行此操作,但它们非常复杂并且依赖于非标准语言扩展。

答案 4 :(得分:1)

您没有说出想要答案的SQL风格。这可能意味着您需要SQL Server中的代码(因为[sql]通常= SO标记用法中的[sql-server])。

但是,如果您(或某些未来的搜索者)正在使用Oracle,这种查询在分析函数中非常简单,在本例中为LAG()。看看:

SQL> select stage_range
  2         , avg(time_diff)/60 as average_time_diff_in_min
  3  from
  4      (
  5          select event_name
  6                 , case when event_name = 'stage 2' then  'stage 1 to 2'
  7                      when event_name = 'stage 3' then  'stage 2 to 3'
  8                      else  '!!!' end as stage_range
  9                 , stage_secs - lag(stage_secs)
 10                              over (order by ts, event_name) as time_diff
 11                 from
 12                     ( select event_name
 13                              , ts
 14                              , to_number(to_char(ts, 'sssss')) as stage_secs
 15                       from timings )
 16      )
 17         where event_name in ('stage 2','stage 3')
 18  group by stage_range
 19  /

STAGE_RANGE  AVERAGE_TIME_DIFF_IN_MIN
------------ ------------------------
stage 1 to 2               2.66666667
stage 2 to 3                        5

SQL>

内部查询中格式的更改是必要的,因为我已将TIME列存储为DATE数据类型,因此我将其转换为秒以使数学更清晰。另一种解决方案是使用Day to Second Interval数据类型。但是这个解决方案实际上就是LAG()

修改

在我对此查询的看法中,我明确没有计算出前一阶段3和后续阶段1之间的差异。这是一个要求问题。

答案 5 :(得分:0)

试试这个

   Select Avg(e.Time - s.Time)
   From Table s
     Join Table e 
         On e.Time = 
             (Select Min(Time)
              From Table
              Where eventname = s.eventname 
                 And time > s.Time)
         And Not Exists 
             (Select * From Table
              Where eventname = s.eventname 
                 And time < s.Time)

对于表示阶段开始的每个记录,此sql将其连接到表示结束的记录,获取结束时间和开始时间之间的差异,并平均这些差异。 Not Exists确保加入到结束记录的起始记录的中间结果集仅包括起始记录为s ...并且第一个连接条件确保只有一个结束记录(具有相同名称和下一个时间值的记录)开始时间)加入了......

要在连接后查看中间结果集,但在取平均值之前,请运行以下命令:

   Select s.EventName,
       s.Time Startime, e.Time EndTime, 
       (e.Time - s.Time) Elapsed
   From Table s
     Join Table e 
         On e.Time = 
             (Select Min(Time)
              From Table
              Where eventname = s.eventname 
                 And time > s.Time)
         And Not Exists 
             (Select * From Table
              Where eventname = s.eventname 
                 And time < s.Time)

答案 6 :(得分:0)

WITH    q AS
        (
        SELECT  'stage 1' AS eventname, CAST('2009-01-01 10:01:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 2' AS eventname, CAST('2009-01-01 10:03:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 3' AS eventname, CAST('2009-01-01 10:06:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 1' AS eventname, CAST('2009-01-01 10:10:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 2' AS eventname, CAST('2009-01-01 10:15:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 3' AS eventname, CAST('2009-01-01 10:21:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 1' AS eventname, CAST('2009-01-01 10:22:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 2' AS eventname, CAST('2009-01-01 10:23:00' AS DATETIME) AS eventtime
        UNION ALL
        SELECT  'stage 3' AS eventname, CAST('2009-01-01 10:29:00' AS DATETIME) AS eventtime
        )
SELECT  (
        SELECT  AVG(DATEDIFF(minute, '2009-01-01', eventtime))
        FROM    q
        WHERE   eventname = 'stage 3'
        ) - 
        (
        SELECT  AVG(DATEDIFF(minute, '2009-01-01', eventtime))
        FROM    q
        WHERE   eventname = 'stage 2'
        )

这依赖于这样一个事实,即您总是拥有完整的阶段组,并且它们总是以相同的顺序排列(即stage 1然后stage 2然后stage 3

答案 7 :(得分:0)

我无法评论,但我必须同意HLGEM。虽然您可以使用提供的数据集判断,但应该让OP意识到仅依赖于一次存在的一组阶段可能过于乐观。


event Name    |    Time

stage 1       |    10:01
stage 2       |    10:03
stage 3       |    10:06
stage 1       |    10:10
stage 2       |    10:15
stage 3       |    10:21
stage 1       |    10:22
stage 2       |    10:23
stage 1       |    10:25     --- new stage 1
stage 2       |    10:28     --- new stage 2
stage 3       |    10:29
stage 3       |    10:34     --- new stage 3

我们不知道环境或创建数据的内容。由OP决定是否正确构建表。

Oracle会通过Google Analytics处理这个问题。像Vilx的回答。