5

如果这令人困惑,请原谅,因为我对 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 个或更多。此外,某些网站(有时)不会一次报告数小时。我只想每小时每个站点选择一个条目(尽可能接近每个小时)。我怎样才能以有效的方式做到这一点?我还需要将此扩展到其他时间范围(例如每个站点每天一个条目 - 尽可能接近午夜)。

感谢您的任何建议。

4

3 回答 3

10

您可以使用DISTINCT ON

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

如果您关心获得的条目,请注意 ORDER BY。

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

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 以选择每个日期感兴趣的特定行。

于 2013-05-09T20:01:53.793 回答
5

您正在寻找每小时最接近的值。有些是在小时之前,有些是在之后。这使得这是一个棘手的问题。

首先,我们需要确定在特定小时内有效的值范围。为此,我会考虑从一小时前的 15 分钟到之后的 45 分钟的任何时间作为那个小时。因此,2:00 的考虑时间从 1:45 到 2:45(任意,但对您的数据来说似乎是合理的)。我们可以通过将时间戳移动 15 分钟来做到这一点。

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

我们可以将这些规则放入 SQL 语句中,使用row_number()

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;
于 2013-05-09T21:00:56.547 回答
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

然后,我会根据您的站点 id 上的站点日志以及 CTE 时间点和 LOG 时间点之间的最小绝对差值离开加入该 CTE。

这样,您就可以确保每个站点每个间隔都有一行。

PS 对于一个长时间没有打电话回家的网站,它最近的电话输入时间戳将被重复多次,作为最接近的可用时间戳。

于 2013-05-09T22:21:09.967 回答