Sql 查询Postgres中连续列的“运行”
我有一张桌子:Sql 查询Postgres中连续列的“运行”,sql,postgresql,gaps-and-islands,Sql,Postgresql,Gaps And Islands,我有一张桌子: create table table1 (event_id integer, event_time timestamp without time zone); insert into table1 (event_id, event_time) values (1, '2011-01-01 00:00:00'), (2, '2011-01-01 00:00:15'), (3, '2011-01-01 00:00:29'), (4, '2011-01-01 00:00:58'), (
create table table1 (event_id integer, event_time timestamp without time zone);
insert into table1 (event_id, event_time) values
(1, '2011-01-01 00:00:00'),
(2, '2011-01-01 00:00:15'),
(3, '2011-01-01 00:00:29'),
(4, '2011-01-01 00:00:58'),
(5, '2011-01-02 06:03:00'),
(6, '2011-01-02 06:03:09'),
(7, '2011-01-05 11:01:31'),
(8, '2011-01-05 11:02:15'),
(9, '2011-01-06 09:34:19'),
(10, '2011-01-06 09:34:41'),
(11, '2011-01-06 09:35:06');
我想构造一个语句,使给定的事件可以返回从该事件开始的事件“运行”的长度。运行定义为:
如果两个事件相距不超过30秒,则两个事件同时运行。
如果A和B在一起运行,B和C在一起运行,则A在一起运行
和C。
但是,我的查询不需要在时间上倒退,因此,如果我在事件2上选择,那么只有事件2、3和4应该被计算为从2开始的事件运行的一部分,而3应该作为运行的长度返回
有什么想法吗?我被难住了 可能是这样的:
WITH x AS (
SELECT event_time
,row_number() OVER w AS rn
,lead(event_time) OVER w AS next_time
FROM table1
WHERE event_id >= <start_id>
WINDOW w AS (ORDER BY event_time, event_id)
)
SELECT COALESCE(
(SELECT x.rn
FROM x
WHERE (x.event_time + interval '30s') < x.next_time
ORDER BY x.rn
LIMIT 1)
,(SELECT count(*) FROM x)
) AS run_length
事件时间与起始行相同但事件id较小的行仍将被忽略
在一次运行直到结束的特殊情况下,没有找到结束,也没有返回行。COALESCE返回所有行的计数。您可以在日期差异语句中将一个表连接到它本身。实际上,这是postgres,一个简单的减号 此子查询将查找作为“开始事件”的所有记录。也就是说,在事件发生前30秒内没有其他事件记录的所有事件记录:
(Select a.event_id, a.event_time from
(Select event_id, event_time from table1) a
left join
(select event_id, event_time from table1) b
on a.event_time - b.event_time < '00:00:30' and a.event_time - b.event_time > '00:00:00'
where b.event_time is null) startevent
通过一些更改…相同的逻辑,除了拾取“结束”事件:
(Select a.event_id, a.event_time from
(Select event_id, event_time from table1) a
left join
(select event_id, event_time from table1) b
on b.event_time - a.event_time < '00:00:30' and b.event_time - a.event_time > '00:00:00'
where b.event_time is null) end_event
现在,我们可以将这些连接在一起,将哪个开始事件关联到哪个结束事件:
还在写…有两种方法可以做到这一点。我假设只有这个示例具有线性ID号,因此您希望将开始事件时间与结束事件时间合并,使事件时间的正差最小
这是我的最终结果…有点嵌套了很多子选择
select a.start_id, case when a.event_id is null then t1.event_id::varchar else 'single event' end as end_id
from
(select start_event.event_id as start_id, start_event.event_time as start_time, last_event.event_id, min(end_event.event_time - start_event.event_time) as min_interval
from
(Select a.event_id, a.event_time from
(Select event_id, event_time from table1) a
left join
(select event_id, event_time from table1) b
on a.event_time - b.event_time < '00:00:30' and a.event_time - b.event_time > '00:00:00'
where b.event_time is null) start_event
inner join
(Select a.event_id, a.event_time from
(Select event_id, event_time from table1) a
left join
(select event_id, event_time from table1) b
on b.event_time - a.event_time < '00:00:30' and b.event_time - a.event_time > '00:00:00'
where b.event_time is null) end_event
on end_event.event_time > start_event.event_time
--check for only event
left join
(Select a.event_id, a.event_time from
(Select event_id, event_time from table1) a
left join
(select event_id, event_time from table1) b
on b.event_time - a.event_time < '00:00:30' and b.event_time - a.event_time > '00:00:00'
where b.event_time is null) last_event
on start_event.event_id = last_event.event_id
group by 1,2,3) a
left join table1 t1 on t1.event_time = a.start_time + a.min_interval
结果为开始id、结束id:
一,;4.
5.6.
7.单一事件
8.单一事件
9;十一,
我必须使用第三个左连接来选择单个事件作为检测开始事件和结束事件的方法。最终结果位于ID中,如果您需要的信息与ID不同,则可以将其链接回原始表。如果您有数百万个事件,则不确定此解决方案将如何扩展……这可能是一个问题。以下是递归CTE解决方案。孤岛和缺口问题自然适用于递归CTE
WITH RECURSIVE runrun AS (
SELECT event_id, event_time
, event_time - ('30 sec'::interval) AS low_time
, event_time + ('30 sec'::interval) AS high_time
FROM table1
UNION
SELECT t1.event_id, t1.event_time
, LEAST ( rr.low_time, t1.event_time - ('30 sec'::interval) ) AS low_time
, GREATEST ( rr.high_time, t1.event_time + ('30 sec'::interval) ) AS high_time
FROM table1 t1
JOIN runrun rr ON t1.event_time >= rr.low_time
AND t1.event_time < rr.high_time
)
SELECT DISTINCT ON (event_id) *
FROM runrun rr
WHERE rr.event_time >= '2011-01-01 00:00:15'
AND rr.low_time <= '2011-01-01 00:00:15'
AND rr.high_time > '2011-01-01 00:00:15'
;
我们可以假设事件id没有间隙吗?或者我们必须假设间隙吗?您对事件2上的select的确切含义是什么?你能告诉我们你的样品数据的期望输出吗?
WITH RECURSIVE runrun AS (
SELECT event_id, event_time
, event_time - ('30 sec'::interval) AS low_time
, event_time + ('30 sec'::interval) AS high_time
FROM table1
UNION
SELECT t1.event_id, t1.event_time
, LEAST ( rr.low_time, t1.event_time - ('30 sec'::interval) ) AS low_time
, GREATEST ( rr.high_time, t1.event_time + ('30 sec'::interval) ) AS high_time
FROM table1 t1
JOIN runrun rr ON t1.event_time >= rr.low_time
AND t1.event_time < rr.high_time
)
SELECT DISTINCT ON (event_id) *
FROM runrun rr
WHERE rr.event_time >= '2011-01-01 00:00:15'
AND rr.low_time <= '2011-01-01 00:00:15'
AND rr.high_time > '2011-01-01 00:00:15'
;
event_id | event_time | low_time | high_time
----------+---------------------+---------------------+---------------------
2 | 2011-01-01 00:00:15 | 2010-12-31 23:59:45 | 2011-01-01 00:00:45
3 | 2011-01-01 00:00:29 | 2010-12-31 23:59:45 | 2011-01-01 00:01:28
4 | 2011-01-01 00:00:58 | 2010-12-31 23:59:30 | 2011-01-01 00:01:28
(3 rows)