В Postgres вы можете использовать generate_series()
для генерации серии данных.Я бы начал с генерации серии чисел, а затем JOIN
с исходными данными, чтобы создать 15-минутные интервалы.Внутренний запрос может использоваться для предварительного вычисления начальных и конечных границ.
Рассмотрим следующий запрос, демонстрирующий логику округления меток времени до 15 минут и JOIN
таблицы с сериями:
SELECT *
FROM generate_series(0, 99, 1) t(x)
INNER JOIN (
SELECT
f.*,
DATE_TRUNC('hour', datetimeconnect)
+ DATE_PART('minute', datetimeconnect )::int / 15 * interval '15 min' connect_15min,
DATE_TRUNC('hour', datetimedisconnect)
+ DATE_PART('minute', datetimedisconnect)::int / 15 * interval '15 min' disconnect_15min
FROM f_contact f
) c
ON c.disconnect_15min >= c.connect_15min + ((t.x * 15) || ' minute')::interval
ORDER BY c.datetimeconnect, t.x;
Например, для agent = 2011
это вернет:
| x | agent | datetimeconnect | datetimedisconnect | duration | connect_15min | disconnect_15min |
| --- | ----- | ------------------------ | ------------------------ | -------- | ------------------------ | ------------------------ |
| 0 | 20011 | 2019-03-11T08:47:40.000Z | 2019-03-11T09:30:10.000Z | 2550 | 2019-03-11T08:45:00.000Z | 2019-03-11T09:30:00.000Z |
| 1 | 20011 | 2019-03-11T08:47:40.000Z | 2019-03-11T09:30:10.000Z | 2550 | 2019-03-11T08:45:00.000Z | 2019-03-11T09:30:00.000Z |
| 2 | 20011 | 2019-03-11T08:47:40.000Z | 2019-03-11T09:30:10.000Z | 2550 | 2019-03-11T08:45:00.000Z | 2019-03-11T09:30:00.000Z |
| 3 | 20011 | 2019-03-11T08:47:40.000Z | 2019-03-11T09:30:10.000Z | 2550 | 2019-03-11T08:45:00.000Z | 2019-03-11T09:30:00.000Z |
Теперь мы можем вычислить продолжительность в предложении FROM
.Хитрость заключается в том, чтобы правильно обрабатывать первый и последний интервалы, используя LEAST()
и GREATEST()
(обратите внимание, что duration
не используется для вычисления):
SELECT
agent,
c.connect_15min + ( t.x * 15 || ' minute' )::interval interval_start_15min,
EXTRACT(EPOCH FROM (
LEAST(datetimedisconnect, c.connect_15min + ( (t.x + 1) * 15 || ' minute' )::interval)
- GREATEST(datetimeconnect, c.connect_15min + ( t.x * 15 || ' minute' )::interval )
)) duration
FROM generate_series(0, 99, 1) t(x)
INNER JOIN (
SELECT
f.*,
DATE_TRUNC('hour', datetimeconnect)
+ DATE_PART('minute', datetimeconnect )::int / 15 * interval '15 min' connect_15min,
DATE_TRUNC('hour', datetimedisconnect)
+ DATE_PART('minute', datetimedisconnect)::int / 15 * interval '15 min' disconnect_15min
FROM f_contact f
) c
ON c.disconnect_15min >= c.connect_15min + ((t.x * 15) || ' minute')::interval
ORDER BY agent, interval_start_15min;
Это демо на DB Fiddle возвращает:
| agent | interval_start_15min | duration |
| ----- | ------------------------ | -------- |
| 20011 | 2019-03-11T08:45:00.000Z | 740 |
| 20011 | 2019-03-11T09:00:00.000Z | 900 |
| 20011 | 2019-03-11T09:15:00.000Z | 900 |
| 20011 | 2019-03-11T09:30:00.000Z | 10 |
| 20024 | 2019-03-18T12:00:00.000Z | 840 |
| 20024 | 2019-03-18T12:15:00.000Z | 900 |
| 20024 | 2019-03-18T12:30:00.000Z | 900 |
| 20024 | 2019-03-18T12:45:00.000Z | 900 |
| 20024 | 2019-03-18T13:00:00.000Z | 90 |