在postgres中合并时间戳记间隔

时间:2020-03-08 20:12:17

标签: postgresql timestamp intervals

我有以下数据,其中跟踪了两个不同设备上的活动:

CREATE TABLE input_data
(
    device "varchar",
    activity "varchar",
    time_from time,
    time_to time);

INSERT INTO input_data (device, activity, time_from, time_to) VALUES
     ('pc', 'netflix', '2020-01-01 12:30:00', '2020-01-01 14:00:00'),
     ('phone', 'call', '2020-01-01 12:58:40', '2020-01-01 13:05:00');

我想查看同时在两个设备上花费的时间间隔:

CREATE TABLE desired_result
    (
        pc_activity "varchar",
        phone_activity "varchar",
        time_from time,
        time_to time);

 INSERT INTO desired_result (pc_activity, phone_activity, time_from, time_to) VALUES
         ('netflix', 'NA', '2020-01-01 12:30:00', '2020-01-01 12:58:40'),
         ('netflix', 'call', '2020-01-01 12:58:40', '2020-01-01 13:05:00'),
         ('netflix', 'NA', '2020-01-01 13:05:00', '2020-01-01 14:00:00')

我如何在Postgres中获得所需的结果?

1 个答案:

答案 0 :(得分:0)

可能有一个更有效的解决方案,但要达到以下所需的结果:

/* collect all time stamp changes in one column */
WITH cte_raw_intervals AS (
SELECT time_from AS time_stamp from input_data
UNION
SELECT time_to AS time_stamp from input_data
order by time_stamp
),

/* create sorted table of all time stamp changes */
cte_sorted_intervals AS (
select *, 
ROW_NUMBER() OVER(ORDER BY time_stamp) AS INTERVAL_ID
from cte_raw_intervals),

/* calculate end time for each time stamp */
cte_intervals AS (
SELECT a.interval_id, a.time_stamp AS time_from ,b.time_stamp AS time_to
FROM cte_sorted_intervals AS a LEFT JOIN cte_sorted_intervals AS b 
ON a.INTERVAL_ID+1 = b.INTERVAL_ID
WHERE b.time_stamp IS NOT NULL),

/* attach each activity back to the new time stamp intervals */
cte_union_results AS 
(SELECT cte_intervals.*, input_data.device, input_data.activity from cte_intervals , input_data
WHERE cte_intervals.time_from >= input_data.time_from
AND cte_intervals.time_to <= input_data.time_to)

/* cross tab the union table results into the unique intervals */
SELECT 
b.activity as pc_activity, c.activity as phone_activity, 
a.time_from, b.time_to FROM cte_intervals as a 
LEFT JOIN cte_union_results as b
ON a.time_from = b.time_from AND b.device = 'pc'
LEFT JOIN cte_union_results as c
ON a.time_from = c.time_from AND c.device = 'phone'