Підсумковий інтервал дат в межах одного стовпця


10

Як найкраще підсумовувати відмінності діапазону дат в одному стовпчику між перемежованими рядками? У мене стовпець Datetime і хочу обчислити різницю між рядками. Я хочу різниці в секундах. Це питання не про те, як розібратися в двох часових позначках, а більше зосереджено на тому, як найбільш ефективно обчислити між рядками в одній таблиці. У моєму випадку кожен рядок має тип події дати, який логічно пов'язує 2 рядки.

Деталі, пов’язані з тим, як згрупувати типи подій початку та кінця. (Запитання Андрія М.) Починається і закінчується "слід" послідовно. Якщо старт не має наступного кінця, його слід залишити без суми. Переходимо до наступного початку, щоб побачити, чи закінчився він. До суми загальних секунд слід додати лише поспіль пари "Початок - Кінець".

Робота в postgresql 9.x ...

Приклад даних у таблиці;

eventtype, eventdate
START, 2015-01-01 14:00
END, 2015-01-01 14:25
START, 2015-01-01 14:30
END, 2015-01-01 14:43
START, 2015-01-01 14:45
END, 2015-01-01 14:49
START, 2015-01-01 14:52
END, 2015-01-01 14:55

Зауважте, усі дати початку та закінчення будуть послідовними.

Ось моя перша спроба. Здається, працює.

SELECT 
-- starts.*
SUM(EXTRACT(EPOCH FROM (eventdate_next - eventdate))) AS duration_seconds
FROM
( 
    WITH x AS (
        SELECT *, dense_rank() OVER (ORDER BY eventdate) AS rnk
        FROM   table
        AND eventdate > '2015-01-01 00:00:00.00'
        AND eventdate < '2016-01-01 23:59:59.59' 
        )
    SELECT x.eventdate, x.eventtype, y.eventdate AS eventdate_next,  y.eventtype AS eventtype_next
    FROM   x
    LEFT   JOIN (SELECT DISTINCT eventdate, eventtype, rnk FROM x) y ON y.rnk = (x.rnk + 1)
    ORDER  BY x.eventdate
) starts
WHERE
eventtype = 'START'   
GROUP BY eventtype 

Моя перша спроба заснована на чудовому прикладі з stackoverflow Postgres 9.1 - Отримання наступного значення

Примітка; Ви можете прокоментувати групу BY та SUM та скасувати коментарі до початку. *, Щоб отримати запис за кожну окрему тривалість, що надходить на суму.

Відповіді:


10

Ви можете використовувати LEADаналітичну функцію для отримання наступних рядків eventtypeта eventdateпоряд із даними поточного рядка:

SELECT
  eventtype,
  eventdate,
  LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
  LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
FROM
  atable
WHERE
      eventdate >= '2015-01-01 00:00:00.00'
  AND eventdate <  '2016-01-01 23:59:59.59'

Використовуючи вищезазначений запит як похідну таблицю, ви можете додатково відфільтрувати результат eventtype = 'START' AND nexttype = 'END'і отримати загальну різницю:

SELECT
  SUM(EXTRACT(EPOCH FROM (nextdate - eventdate))) AS duration_seconds
FROM
  (
    SELECT
      eventtype,
      eventdate,
      LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
      LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
    FROM
      atable
    WHERE
          eventdate >= '2015-01-01 00:00:00.00'
      AND eventdate <  '2016-01-01 23:59:59.59'
  ) AS s
WHERE
      eventtype = 'START'
  AND nexttype  = 'END'
;

Як невеликий варіант, ви можете реалізувати підзапит як CTE:

WITH cte AS
  (
    SELECT
      eventtype,
      eventdate,
      LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
      LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
    FROM
      atable
    WHERE
          eventdate >= '2015-01-01 00:00:00.00'
      AND eventdate <  '2016-01-01 23:59:59.59'
  )
SELECT
  SUM(EXTRACT(EPOCH FROM (nextdate - eventdate))) AS duration_seconds
FROM
  cte
WHERE
      eventtype = 'START'
  AND nexttype  = 'END'
;

Це перезапис може мати наслідки для продуктивності, оскільки на відміну від похідної таблиці, CTE матеріалізується в PostgreSQL. Тестування повинно виявити, чи є різниця, і якщо так, то який варіант краще для вас.


Андрій, спасибі! Я спробую версію CTE і побачу, як це допомагає.
C Smith
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.