选择相隔一秒的行

时间:2019-03-04 17:05:40

标签: sql postgresql

我正在收集一堆记录,每个记录都有一个时间戳。问题是我每秒收集大量记录,并且它们占用大量磁盘空间,并且当数据的使用时间超过一天时,我不需要这种粒度级别。我仍然想保留一些数据,比如说每秒大约一个记录,并删除所有其他数据。

例如:

Row TimeStamp(in seconds)
1       2
2       2.1 <--- delete
3       2.4 <--- delete
4       3
5       3.3 <--- delete
6       3.95
7       4.5 <--- delete
8       5.1

这样,我保留了大约一秒钟的记录,同时删除了两者之间的所有记录。有没有办法使用SQL做到这一点?

我想一种方法是遍历每一行并保持它们之间的全局时间戳差异,并在差异超过一秒时保存行,尽管我不确定如何在SQL中做到这一点。

2 个答案:

答案 0 :(得分:1)

如果只需要保持固定的粒度,则可以使用日历槽位表(此处是使用generate_series动态生成的),对于日历的每一行,请使用日期/时间功能。将这些行合并并分配给每个日历槽后,可以使用DISTINCT ON根据任意表达式选择“最佳”行。像这样:

CREATE TEMP TABLE measurement (id integer, ts timestamp);

COPY measurement (id, ts) FROM STDIN;
1   2019-03-05 00:00:02
2   2019-03-05 00:00:02.1
3   2019-03-05 00:00:02.4
4   2019-03-05 00:00:03
5   2019-03-05 00:00:03.3
6   2019-03-05 00:00:03.95
7   2019-03-05 00:00:04.5
8   2019-03-05 00:00:05.1
\.

SELECT DISTINCT ON (day.ts) m.*
FROM (
    SELECT '2019-03-05 00:00:00'::timestamp + (s||' seconds')::interval as ts
    FROM generate_series(0, 86399) AS s
) AS day
JOIN measurement m
  ON (m.ts > day.ts - '0.5 s'::interval
      AND m.ts <= day.ts + '0.5 s'::interval)
ORDER BY day.ts, abs(extract(epoch from day.ts - m.ts))
;

/* result: 
 id |           ts           
----+------------------------
  1 | 2019-03-05 00:00:02
  4 | 2019-03-05 00:00:03
  6 | 2019-03-05 00:00:03.95
  8 | 2019-03-05 00:00:05.1
(4 rows)
*/

答案 1 :(得分:1)

我建议您仅每秒记录第一条。那应该是:

select distinct on (date_trunc('second', timestamp)) t.*
from t
order by date_trunc('second', timestamp), timestamp asc;

如果您的时间戳确实是数字,则可以使用:

select distinct on (trunc(timestamp)) t.*
from t
order by trunc(timestamp), timestamp;

Here是db <>小提琴。