Находить среднее между многими Oracle отметками времени? - PullRequest
1 голос
/ 23 марта 2020

Итак, я пытаюсь найти среднее из списка временных отметок, используя Oracle. У меня есть таблица, которая растет для itemX. Каждый раз, когда вызывается itemX, он помещает значение в мою таблицу. Это могут быть дни, месяцы, годы данных и метки времени. Меня беспокоит только среднее число последних 10 временных отметок, и только если они были за последние 3 часа.

У меня есть данные, которые выглядят следующим образом ...

ROW_NUM itemX   DEVICE_TIMESTAMP
1   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:46:51.000000 PM
2   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:45:50.000000 PM
3   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:44:49.000000 PM
4   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:43:49.000000 PM
5   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:42:49.000000 PM
6   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:41:48.000000 PM
7   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:40:47.000000 PM
8   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:39:46.000000 PM
9   9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:38:45.000000 PM
10  9094E4E56CAEF8D7E0531965000A285C    3/23/2020 12:37:44.000000 PM

Использование:

select row_number() over(order by device_timestamp desc) row_num, 
                itemX, device_timestamp 
            from  tracks_report 
            where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE 
            and itemX = '9094E4E56CAEF8D7E0531965000A285C'
            order by device_timestamp desc
            FETCH NEXT 10 ROWS ONLY

То, что я хочу получить, - это среднее время между этими 10 строками. Я попытался разбить это на секунды и минуты, сложив их, разделив на 10, а затем усреднив. Но мои ценности не верны. Это будет функция, где я могу вызывать ее на основе идентификатора itemX.

Есть предложения? Я должен получить что-то около 60 секунд. Но в результате мой разрыв и среднее значение составляют всего около 47 секунд.

Ответы [ 2 ]

4 голосов
/ 23 марта 2020

Вы можете использовать функции LAG / LEAD analyti c, чтобы найти предыдущее / следующее значение, а затем вычесть, чтобы получить интервал и извлечь компоненты и среднее значение:

SELECT itemx,
       AVG(
         EXTRACT( HOUR   FROM diff_since_last ) * 3600
       + EXTRACT( MINUTE FROM diff_since_last ) * 60 
       + EXTRACT( SECOND FROM diff_since_last )
       ) AS average_seconds_difference
FROM   (
  SELECT ROW_NUMBER() OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
           AS rn,
         itemx,
         device_timestamp,
         device_timestamp
           - LEAD( device_timestamp )
             OVER ( PARTITION BY itemx ORDER BY device_timestamp DESC )
             AS diff_since_last
  FROM   tracks_report t
) t
WHERE  rn <= 10
AND    FROM_TZ( device_timestamp, 'UTC' ) >= SYSTIMESTAMP - INTERVAL '3' HOUR
GROUP BY itemx

Для тестовых данных:

CREATE TABLE tracks_report ( itemX, DEVICE_TIMESTAMP ) AS
SELECT 'A1',
        CAST( TRUNC( SYSTIMESTAMP, 'HH' ) AS TIMESTAMP )
          + INTERVAL '1:01.000001' MINUTE TO SECOND * ( LEVEL - 1 )
FROM   DUAL
CONNECT BY LEVEL <= 20

Это выводит:

ITEMX | AVERAGE_SECONDS_DIFFERENCE
:---- | -------------------------:
A1    |                  61.000001

(Примечание: среднее включает дробные секунды, которые, я полагаю, важны, поскольку вы используете TIMESTAMP типы данных, а не DATE типы данных.)

(Примечание 2: это усреднение интервалов от последних 10 временных меток до предыдущей временной метки; поэтому он будет учитывать интервал с 10-й по 11-ю самую последнюю временную метку, даже если эта 11-я временная метка находится за пределами 3-часового диапазона, а 10-я находится в пределах 3 часов. Если вы хотите учитывать только, когда все значения находятся в пределах этого 3-часового диапазона затем переместите фильтр из внешнего запроса во внутренний. И если вы хотите сравнить 9 интервалов между 10 значениями [а не 10 интервалов между 11 значениями], то измените на rn <= 9.) * 1 023 *

дБ <> скрипка здесь

3 голосов
/ 23 марта 2020

Та же самая базовая c идея, что и у @MTO, но она использует ваш оригинальный запрос - включая фильтр / лимит - в CTE:

with cte1 (row_num, itemx, device_timestamp) as (
  select row_number() over(order by device_timestamp desc), 
    itemX,
    device_timestamp
  from tracks_report 
  where device_timestamp >= sys_extract_utc(systimestamp) - INTERVAL '03:00' HOUR TO MINUTE 
  and itemX = '9094E4E56CAEF8D7E0531965000A285C'
  order by device_timestamp desc
  FETCH NEXT 10 ROWS ONLY
)
select row_num,
  itemX,
  device_timestamp,
  device_timestamp
    - lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
    as diff_interval
from cte1;

И затем вы можете получить разницу из интервалов в секунд с extract():

with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
  select row_num,
    itemX,
    device_timestamp,
    device_timestamp
      - lead(device_timestamp) over (partition by itemX order by device_timestamp desc)
      as diff_interval
  from cte1
)
select row_num, itemX, device_timestamp, diff_interval,
  extract(hour from diff_interval) * 3600
    + extract(minute from diff_interval) * 60
    + extract(second from diff_interval) as diff_seconds
from cte2;

И вместо того, чтобы отображать их все, получите среднее значение:

with cte1 (row_num, itemx, device_timestamp) as (
...
),
cte2 (row_num, itemX, device_timestamp, diff_interval) as (
...
)
select avg(
    extract(hour from diff_interval) * 3600
      + extract(minute from diff_interval) * 60
      + extract(second from diff_interval)
  ) as avg_diff_seconds
from cte2;

AVG_DIFF_SECONDS
----------------
      60.7777778

Единственная причина, по которой я до сих пор писал, состоит в том, что он ведет себя по-разному из-за того, где фильтр / предел применяется. При этом рассматривается среднее из 9 интервалов между 10 самыми последними временными метками (если их было много за последние 3 часа). Если вы примените фильтр / предел в конце, тогда он будет включать интервал между 10-м и 11-м, даже если 11-е многократно раньше.

Что правильно, конечно, решать вам, это не так. t совершенно ясно из вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...