【问题标题】:Query result of latest timestamp if required value not available如果需要的值不可用,则查询最新时间戳的结果
【发布时间】:2019-09-03 01:39:10
【问题描述】:

我有一个 psql 数据库,其中每分钟更新大约数千个键值的结果。出于报告目的,我需要在全时准确的每小时结果,即 9:00、10:00) 等。我的数据是这样的:

timestamp       tag value
2019-06-06 06:00:00 x   123
2019-06-06 06:00:00 y   456
2019-06-06 06:01:00 x   123
2019-06-06 06:01:00 y   656
2019-06-06 06:02:00 x   123 
2019-06-06 06:02:00 y   333 
.......
.......
2019-06-06 06:59:00 x   2232
2019-06-06 06:59:00 y   654
2019-06-06 07:00:00 x   5645
2019-06-06 07:00:00 y   54654

并得到如下结果:,

timestamp               tag value
2019-06-06 06:00:00     x   123
2019-06-06 06:00:00     y   456
2019-06-06 07:00:00     x   5645
2019-06-06 07:00:00     y   54654
...
.....
......
2019-06-09 07:00:00     x   5645
2019-06-09 07:00:00     y   54654

我使用了以下代码:

select *
from test
where date_trunc('hour', "timestamp") = "timestamp";

但是根据上面的查询结果,会给出整点的准确时间。但有时,其中一些密钥并没有像这样在整个小时内准确更新:

timestamp       tag value
2019-06-06 05:59:00 x   123
2019-06-06 05:59:00 y   456
2019-06-06 06:01:00 x   123
2019-06-06 06:01:00 y   656

在上述情况下,我将在 6:00:00 得到空结果。

我想要在上述情况下自动传递最后一个值的查询,即 05:59:00 的值。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    您需要生成您感兴趣的时间范围,而不仅仅是“开始”。所以

        with test as 
       ( select * from
              ( values ('2019-06-06 05:59:00'::timestamp without time zone, 'x', 123)    
                     , ('2019-06-06 05:59:00'::timestamp without time zone, 'y', 456)
                     , ('2019-06-06 06:01:00'::timestamp without time zone, 'x', 123)           
                     , ('2019-06-06 06:01:00'::timestamp without time zone, 'y', 656)          
              )
            as t (act_ts ,tag, value  
            )        
        )   
    select act_ts,tag,value
         , lower(tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)')) as from_time 
         , upper(tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)')) as time     
      from test
     where act_ts <@ tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)') 
     order by tag,lower(tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)') );
    

    上面通过tsrange函数生成一个每小时的时间范围:

    tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)'))
    

    上面会在 act_ts 小时之间生成一个时间戳(我希望您的列名实际上不是“时间戳”)。注意最后一个参数'[)'。这告诉 Postgres 包括下限值但排除上限值。参考 Postgres Range Types。 我添加了一个额外的列和一个 order by 用于演示目的,这在实现查询中是不必要的。那可能只是:

    select act_ts,tag,value
      from test
     where act_ts <@ tsrange(date_trunc('hour',act_ts),date_trunc('hour',act_ts+interval '1 hour'), '[)');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-09
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多