我有一个时间序列数据,其中我试图在特定时间间隔内按顺序查找连续的记录条纹,并按每个连续记录系列进行分组。例如,如果每个集合(组)的记录之间的时间间隔为 5 分钟,则 5 分钟内的任何下一条记录都将包含在该集合中,并且任何超过 5 分钟的记录都将结束该集合(组)。接下来的两个记录将在 5 分钟内出现一个新的集合(组)。
**分钟分隔不在表中,是在查询中计算的
| | | | | |
|----|---------------------|-----------------------------------|----------|------------------------------------------------------------|
| id | timestamp | minute separation (Calculated **) | group | notes |
| 1 | 2018-02-13T01:18:00 | 0 | Group 1 | |
| 2 | 2018-02-13T01:22:00 | 4 | Group 1 | |
| 3 | 2018-02-13T01:25:00 | 3 | Group 1 | |
| 4 | 2018-02-13T01:31:00 | 6 | No Group | breaks group 1 |
| 5 | 2018-02-13T01:38:00 | 7 | No Group | not within interval on either side |
| 6 | 2018-02-13T01:44:00 | 6 | Group 2 | Start of group 2 |
| 7 | 2018-02-13T01:47:00 | 3 | Group 2 | |
| 8 | 2018-02-13T01:48:00 | 1 | Group 2 | |
| 9 | 2018-02-13T01:49:00 | 1 | Group 2 | |
| 10 | 2018-02-13T01:51:00 | 2 | Group 2 | |
| 11 | 2018-02-13T01:57:00 | 6 | Group 3 | Breaks Group 2, included in next group as start of group 3 |
| 12 | 2018-02-13T01:59:00 | 2 | Group 3 | |
| 13 | 2018-02-13T02:01:00 | 2 | Group 3 | |
| 14 | 2018-02-13T02:02:00 | 1 | Group 3 | |
| 15 | 2018-02-13T02:08:00 | 6 | No Group | Breaks group 3 |
| 16 | 2018-02-13T02:15:00 | 7 | No Group | |
| 17 | 2018-02-13T02:22:00 | 7 | No Group | |
Run Code Online (Sandbox Code Playgroud)
我可以按顺序找到 2 行之间的差异并提取它们,但我不确定如何提取一系列 n+1 行。
我的工作示例在这里: http://sqlfiddle.com/#! 17/e9fa1/7
示例数据 SQL 插入:
CREATE TABLE time_series (
id SERIAL UNIQUE,
name TEXT,
timestamp TIMESTAMPTZ
);
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:18:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:22:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:25:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:31:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:38:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:44:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:47:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:48:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:49:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:51:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:57:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T01:59:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T02:01:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T02:02:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T02:08:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T02:15:00');
INSERT into time_series (name,timestamp) VALUES ('Test','2018-02-13T02:22:00');
Run Code Online (Sandbox Code Playgroud)
工作查询:
WITH my_series AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY timestamp) AS rn
FROM time_series
)
SELECT o1.id AS id1, o1.timestamp AS date1, o2.id AS id2, o2.timestamp AS date2, ABS(EXTRACT(EPOCH FROM (o1.timestamp - o2.timestamp))) AS diff
FROM my_series as o1 JOIN my_series as o2
ON o1.rn + 1 = o2.rn
WHERE ABS(EXTRACT(EPOCH FROM (o1.timestamp - o2.timestamp))) < 300;
Run Code Online (Sandbox Code Playgroud)
我需要将每个组作为一组返回(这将起作用,因为我应该能够重复查询,并注意到查询结束以开始下一个查询的时间戳,尽管这似乎不是很有效),或者返回所有组标记为组,如下所示:
期望的结果:
| | | | | |
|----|---------------------|-----------------------------------|----------|------------------------------------------------------------|
| id | timestamp | minute separation (Calculated **) | group | notes |
| 1 | 2018-02-13T01:18:00 | 0 | 1 | |
| 2 | 2018-02-13T01:22:00 | 4 | 1 | |
| 3 | 2018-02-13T01:25:00 | 3 | 1 | |
| 6 | 2018-02-13T01:44:00 | 6 | 2 | |
| 7 | 2018-02-13T01:47:00 | 3 | 2 | |
| 8 | 2018-02-13T01:48:00 | 1 | 2 | |
| 9 | 2018-02-13T01:49:00 | 1 | 2 | |
| 10 | 2018-02-13T01:51:00 | 2 | 2 | |
| 11 | 2018-02-13T01:57:00 | 6 | 3 | |
| 12 | 2018-02-13T01:59:00 | 2 | 3 | |
| 13 | 2018-02-13T02:01:00 | 2 | 3 | |
| 14 | 2018-02-13T02:02:00 | 1 | 3 | |
Run Code Online (Sandbox Code Playgroud)
您想使用lag()和lead()。我会枚举所有组,甚至是只有一行的组:
select s.*,
sum( (timestamp >= prev_timestamp + interval '5 minute' or prev_timestamp is null)::int ) over (order by timestamp) as grp
from (select s.*,
lag(timestamp) over (order by timestamp) as prev_timestamp,
lead(timestamp) over (order by timestamp) as next_timestamp
from my_series s
) s;
Run Code Online (Sandbox Code Playgroud)
对于您的实际问题来说,逻辑有点复杂。我认为这可以解决问题:
select s.*,
(case when timestamp > prev_timestamp + interval '5 minute' and
timestamp < next_timestamp - interval '5 minute' and
then NULL
else sum( (timestamp >= prev_timestamp + interval '5 minute' and next_timestamp < timestamp + interval '5 minute')::int ) over (order by timestamp)
end) as grp
from (select s.*,
lag(timestamp) over (order by timestamp) as prev_timestamp,
lead(timestamp) over (order by timestamp) as next_timestamp
from my_series s
) s;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1035 次 |
| 最近记录: |