我有一个包含时间戳范围和用户ID的PostgreSQL(9.4)表格,我需要将任何重叠的范围(具有相同的用户ID)合并为单个记录。我尝试了一组复杂的基本表达式(CTE)来实现这一点,但我们真实表格中的一些边缘情况使事情变得复杂。我得出结论,我可能需要使用递归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
处的记录)。我需要检测到分区开头的所有记录。在此之后,我需要将任何重叠的记录分组在一起,以找到最早会话的开始和最后会话的结束以终止。
我确信有一种方法可以做到这一点,但我可能忽略了什么。如何折叠这些重叠的记录?