在Postgres中,您可以使用
generate_series()
生成数据序列。我会从生成一系列数字开始,然后将其与原始数据
JOIN
起来,以生成15分钟的时间段。内部查询可用于预先计算起始和结束边界。
考虑以下查询,展示了将时间戳舍入为15分钟并使用系列表将表连接的逻辑:
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 |