Postgresql选择按给定间隔隔开的记录范围

时间:2011-03-15 03:28:00

标签: sql postgresql

我正在尝试确定是否有可能,仅使用sql for postgres,以给定的间隔选择一系列时间顺序记录。

假设我有60条记录,在给定的一小时内每分钟有一条记录。我想以5分钟的间隔为那个小时选择记录。结果行应该是12个记录,每个记录相隔5分钟。

目前,这是通过选择全部记录然后循环结果并以给定间隔拉出记录来实现的。我试图看看我是否可以在sql中执行此操作,因为我们的数据库很大,我们可能正在处理成千上万的记录。

有什么想法吗?

5 个答案:

答案 0 :(得分:6)

是的,你可以。一旦掌握了它,它就变得非常简单。我认为它是SQL的一个珠宝,它在PostgreSQL中特别容易,因为它具有出色的时间支持。通常,复杂的函数可以在SQL中变成非常简单的查询,可以扩展和正确编制索引。

这使用generate_series绘制间隔1分钟的样本时间戳。外部查询然后提取分钟并使用模数来查找相隔5分钟的值。

select
    ts,
    extract(minute from ts)::integer as minute

    from
    ( -- generate some time stamps - one minute apart
        select
            current_time + (n || ' minute')::interval  as ts
        from generate_series(1, 30) as n
    ) as timestamps
    -- extract the minute check if its on a 5 minute interval
    where extract(minute from ts)::integer % 5 = 0
    -- only pick this hour 
    and extract(hour from ts) = extract(hour from current_time)
;
         ts         | minute 
--------------------+--------
 19:40:53.508836-07 |     40
 19:45:53.508836-07 |     45
 19:50:53.508836-07 |     50
 19:55:53.508836-07 |     55

注意如何在where子句中添加计算索引(表达式的值将构成索引)可能会导致主要的速度提升。在这种情况下可能不是很有选择性,但要注意很好。

我在PostgreSQL中编写了一个预约系统(它有许多时间逻辑,其中日期间隔不能重叠)并且永远不必诉诸迭代方法。

http://www.amazon.com/SQL-Design-Patterns-Programming-Focus/dp/0977671542是一本很好的书,里面有很多区间的例子。现在很难在书店找到,但非常值得。

答案 1 :(得分:1)

提取分钟数,转换为int4,如果除以5的余数为0,则查看:

select * 
  from TABLE 
  where int4 (date_part ('minute', COLUMN)) % 5 = 0; 

答案 2 :(得分:1)

  • 如果间隔不是基于时间的,你只需要每隔5行;或
  • 如果时间是常规的,并且总是每分钟有一条记录

以下为每5个

提供一条记录
select *
from
(
  select *, row_number() over (order by timecolumn) as rown
  from tbl
) X
where mod(rown, 5) = 1

如果您的时间记录不规律,那么您需要生成一个时间序列(在另一个答案中给出)并将其连接到您的表中,按时间列(从系列中)分组并从您的表中选择MAX时间小于时间列的表。

select thetimeinterval, max(timecolumn)
from ( < the time series subquery > ) X
left join tbl on tbl.timecolumn <= thetimeinterval
group by thetimeinterval

并进一步将其重新加入桌面以获得完整记录(假设时间独特)

select t.* from
tbl inner join
(
    select thetimeinterval, max(timecolumn) timecolumn
    from ( < the time series subquery > ) X
    left join tbl on tbl.timecolumn <= thetimeinterval
    group by thetimeinterval
) y on tbl.timecolumn = y.timecolumn

答案 3 :(得分:0)

这个怎么样:

select min(ts), extract(minute from ts)::integer / 5 
   as bucket group by bucket order by bucket; 

如果您在同一分钟内有两个读数,或者您的读数会跳过一分钟,那么这样做的好处就是做正确的事情。更好的方法是使用min()聚合函数之一,而不是使用first - 您可以在这里找到代码:

http://wiki.postgresql.org/wiki/First_%28aggregate%29

答案 4 :(得分:0)

这假设您的五分钟间隔是“五分之一”,可以这么说。也就是说,你想要07:00,07:05,07:10,而不是07:02,07:07,07:12。它还假设您在同一分钟内没有两行,这可能不是一个安全的假设。

select your_timestamp
from your_table
where cast(extract(minute from your_timestamp) as integer) in (0,5);

如果您可能在同一分钟内有两行时间戳,例如

2011-01-01 07:00:02
2011-01-01 07:00:59

然后这个版本更安全。

select min(your_timestamp)
from your_table
group by (cast(extract(minute from your_timestamp) as integer) / 5)

在视图中包装其中任何一个,然后将其加入基表。