我有一个包含时间戳范围和用户ID的PostgreSQL(9.4)表,并且我需要将任何重叠范围(具有相同的用户标识)合并为一条记录。在PostgreSQL中合并重叠时间范围
我已经尝试了一套复杂的CTE来完成这个任务,但是在我们的(40,000+行)真实表中存在一些使边界事件复杂化的边界情况。我得出的结论是,我可能需要一个递归CTE,但我没有任何运气写它。
这里有一些代码来创建一个测试表并用数据填充它。这不是我们桌子的确切布局,但它足够接近一个例子。
CREATE TABLE public.test
(
id serial,
sessionrange tstzrange,
fk_user_id integer
);
insert into test (sessionrange, fk_user_id)
values
('[2016-01-14 11:57:01-05,2016-01-14 12:06:59-05]', 1)
,('[2016-01-14 12:06:53-05,2016-01-14 12:17:28-05]', 1)
,('[2016-01-14 12:17:24-05,2016-01-14 12:21:56-05]', 1)
,('[2016-01-14 18:18:00-05,2016-01-14 18:42:09-05]', 2)
,('[2016-01-14 18:18:08-05,2016-01-14 18:18:15-05]', 1)
,('[2016-01-14 18:38:12-05,2016-01-14 18:48:20-05]', 1)
,('[2016-01-14 18:18:16-05,2016-01-14 18:18:26-05]', 1)
,('[2016-01-14 18:18:24-05,2016-01-14 18:18:31-05]', 1)
,('[2016-01-14 18:18:12-05,2016-01-14 18:18:20-05]', 3)
,('[2016-01-14 19:32:12-05,2016-01-14 23:18:20-05]', 3)
,('[2016-01-14 18:18:16-05,2016-01-14 18:18:26-05]', 4)
,('[2016-01-14 18:18:24-05,2016-01-14 18:18:31-05]', 2);
我发现,我能做到这一点得到通过,他们开始的时间顺序排列的会话:
select * from test order by fk_user_id, sessionrange
我可以用它来确定单个记录是否与以前相比,使用窗口重叠功能:
SELECT *, sessionrange && lag(sessionrange) OVER (PARTITION BY fk_user_id ORDER BY sessionrange)
FROM test
ORDER BY fk_user_id, sessionrange
但这仅检测单个此前的纪录是否重叠当前的(见记录下id = 6
)。我需要一直检测到分区的开始。
之后,我需要将任何重叠在一起的记录分组,以查找最早会话的开始和最后一个会话的结束。
我确定有一种方法可以做到这一点,我忽略了。我怎样才能折叠这些重叠记录?
我结束了第一个解决方案去,因为它并不需要在所有被调整以适应我真正的模式。这很容易处理,看起来是正确的。我需要做一些额外的测试,但我想我今天晚些时候会回来接受你的回答。谢谢! –
管理做了一些测试,它确实表现出它将我想要的所有方式结合起来。谢谢! –
你的问题对我来说是一个挑战。无法忍受我不能没有这个功能;) – klin