Запрос для вычисления среднего времени между последовательными событиями

Мой вопрос о том, как записать 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
6
задан Jonathan Leffler 22 December 2009 в 16:25
поделиться

8 ответов

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)
);

Параметры могут быть изменены по мере изменения количества ступеней. В настоящее время это установлено, чтобы найти среднее значение между этапами 1 и 2 из трехэтапного процесса.

ИЗМЕНИТЬ пару опечаток

2
ответ дан 8 December 2019 в 13:00
поделиться

Дизайн вашей таблицы ошибочен. Как вы можете сказать, какой этап 1 соответствует этапу 2? Без возможности сделать это, я не думаю, что ваш запрос возможен.

1
ответ дан 8 December 2019 в 13:00
поделиться

Самый простой способ - упорядочить по времени и использовать курсор (tsql) для перебора данных. Поскольку курсоры - это зло, рекомендуется извлекать данные, упорядоченные по времени, в код вашего приложения и выполнять итерацию там. Возможно, есть и другие способы сделать это в SQL, но они будут очень сложными и будут основываться на нестандартных расширениях языка.

1
ответ дан 8 December 2019 в 13:00
поделиться
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'
        )

Это основано на том факте, что у вас всегда есть полные группы этапов, и они всегда идут в одном и том же порядке (то есть, этап 1 , затем этап 2 затем этап 3 )

0
ответ дан 8 December 2019 в 13:00
поделиться

попробуйте это

   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)
0
ответ дан 8 December 2019 в 13:00
поделиться

Аааа и с посыпанием черной магией:

select a.eventName, b.eventName, AVG(DATEDIFF(MINUTE, a.[Time], b.[Time])) as Average from
     (select *, row_number() over (order by [time]) rn from events) a
join (select *, row_number() over (order by [time]) rn from events) b on (a.rn=b.rn-1)
group by
a.eventName, b.eventName

Это даст вам строки типа:

stage3  stage1  2
stage1  stage2  2
stage2  stage3  5

Первый столбец - стартовое событие, второй столбец - конечное событие. Если есть событие 3 сразу после события 1, то оно также будет указано в списке. В противном случае вы должны указать некоторые критерии того, на каком этапе следует какой этап, поэтому время рассчитывается только между ними.

Added: Это должно работать нормально как на Transact-SQL (MSSQL, Sybase), так и на PL/SQL (Oracle, PostgreSQL). Однако я не протестировал его, и все еще могут быть синтаксические ошибки. Это НЕ будет работать ни на одной из версий MySQL.

.
13
ответ дан 8 December 2019 в 13:00
поделиться

Вы не говорите, за какой вкус SQL вы хотите получить ответ. Скорее всего, это означает, что Вам нужен код в SQL-сервере (как [sql] обычно = [sql-сервер] в использовании SO-тегов).

Но на тот случай, если вы (или какой-нибудь будущий искатель) используете 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().

edit

В своем дублете по этому вопросу я явно не вычислил разницу между предыдущим этапом 3 и последующим этапом 1. Это вопрос требований.

1
ответ дан 8 December 2019 в 13:00
поделиться

Я не могу комментировать, но должен согласиться с HLGEM. Хотя вы можете сказать с помощью предоставленного набора данных, операционная система должна знать, что полагаться только на один набор стадий, существующих в одно время, может быть слишком оптимистичной.


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

Мы не знаем ни окружения, ни того, что создаёт данные. Решать, правильно ли построена таблица, зависит от операционной системы.

Оракул справился бы с этим с помощью Analytics. как ответ Вилкса.

.
0
ответ дан 8 December 2019 в 13:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: