如何从时间戳表中每小时选择一行数据?

时间:2013-05-09 19:17:28

标签: sql database postgresql timestamp

打扰一下,如果这令人困惑,因为我对postgresql不是很熟悉。我有一个postgres数据库,其中包含一个充满“站点”的表。每个站点每小时报告一次,当它报告时,它在此表中输入一个条目,如下所示:

site |      tstamp
-----+--------------------
6000 | 2013-05-09 11:53:04
6444 | 2013-05-09 12:58:00
6444 | 2013-05-09 13:01:08
6000 | 2013-05-09 13:01:32
6000 | 2013-05-09 14:05:06
6444 | 2013-05-09 14:06:25
6444 | 2013-05-09 14:59:58
6000 | 2013-05-09 19:00:07

正如您所看到的,时间戳几乎从不在鼻子上,有时在几分钟/秒内彼此会有2个或更多。此外,有些网站不会一次报告几小时(有时)。我想每小时只为每个站点选择一个条目(尽可能接近每小时)。我怎样才能以有效的方式做到这一点?我还需要将其扩展到其他时间范围(例如每个站点每天一个条目 - 尽可能接近午夜)。

感谢您提出的所有建议。

3 个答案:

答案 0 :(得分:9)

您可以使用DISTINCT ON

select distinct on (date_trunc('hour', tstamp)) site, tstamp
from t
order by date_trunc('hour', tstamp), tstamp

如果您关心的是哪个条目,请注意ORDER BY。

或者,您可以使用row_number window function标记感兴趣的行,然后从派生表中剥离每个组中的第一个结果:

select site, tstamp
from (
    select site, tstamp,
           row_number() over (partition by date_trunc('hour', tstamp) order by tstamp) as r
    from t
) as dt
where r = 1

同样,您需要调整ORDER BY以选择每个日期的特定感兴趣行。

答案 1 :(得分:5)

您正在寻找每小时最接近的值。有些是在一小时之前,有些是在之后。这使这成为一个艰难的问题。

首先,我们需要确定适用于特定小时的值范围。为此,我会考虑从小时前15分钟到小时后45分钟的任何事情。因此,2:00的考虑期间从1:45到2:45(任意,但对您的数据似乎是合理的)。我们可以通过将时间戳移动15分钟来实现这一目标。

其次,我们需要获得与小时最接近的值。所以,我们更喜欢1:57到2:05。我们可以通过考虑(57,60 - 57,5,60 - 5)中的第一个值来做到这一点。

我们可以使用row_number()

将这些规则放入SQL语句中
select site, tstamp, usedTimestamp
from (select site, tstamp,
             date_trunc('hour', tstamp + 'time 00:15') as usedTimestamp
             row_number() over (partition by site, to_char(tstamp + time '00:15', 'YYYY-MM-DD-HH24'),
                                order by least(extract(minute from tstamp), 60 - extract(minute from tstamp))
                               ) as seqnum
      from t
     ) as dt
where seqnum = 1;

答案 2 :(得分:1)

对于问题的可扩展性方面。

I also will need to extend this to other time frames (like one entry per site per day

从不同的站点ID集合中,使用(递归)CTE,我将在指定的StartDateTime,EndDateTime范围内构建一个由每小时每小时一个条目(或其他指定间隔)组成的集合。

          SITE..THE DATE-TIME-HOUR
          6000  12.1.2013 00:00:00
          6000  12.1.2013 01:00:00
          .
          .
          . 
          6000  12.1.2013 24:00:00              
          7000  12.1.2013 00:00:00        
          7000  12.1.2013 01:00:00
          .
          .
          . 
          7000  12.1.2013 24:00:00

然后我会将CTE与您的SITES登录站点ID以及CTE时间点与LOG的时间点之间的最小绝对差异联系起来。

通过这种方式,您可确保每个站点每个站点有一行。

P.S。对于长时间没有打电话回家的网站,其最新的电话时间戳将作为最接近的时间戳重复多次。