用于填充多个组的时间序列间隙的postgresql

ygya80vv  于 2021-08-13  发布在  Java
关注(0)|答案(2)|浏览(340)

我有一个这样的表,它跨越了2天的数据捕获时间:

class   timestamp              count

   2       2020-05-20 03:10:00    4
   1       2020-05-21 07:45:00    2
   6       2020-05-20 09:20:00    1
   2       2020-05-21 11:30:00    1
   5       2020-05-21 21:50:00    3
   1       2020-05-21 07:45:00    5
   5       2020-05-20 14:55:00    2

我想创建类似于该模式的输出,但是如果没有匹配的时间戳,则在两天内每隔5分钟创建一次,并用count zeroed out表示。一个类的所有重复时间戳都需要为该时间戳条目求和。所有唯一类都需要分组,顺序应该是时间戳升序。
每一个独特的类都需要以这种方式对待——按类分组,按顺序填写缺失的5分钟时间,按时间戳顺序对该组中具有完全相同时间戳的任何计数求和。整体输出应该按类升序排列。
谢谢你的帮助。

9lowa7mx

9lowa7mx1#

postgres使用 left join . 以下每个时间戳有一行:

select gs.ts, coalesce(sum(t.count), 0)
from generate_series('2020-05-20 00:00:00'::timestamp, '2020-05-21 23:55:00'::timestamp, interval '5 minute') gs(ts) left join
     t
     on t.timestamp = gs.ts
group by gs.ts;

如果你想让这个问题在课堂上得到解决(根据问题的措辞,我真的不知道你的意图),那么就用 cross join 生成行和 left join 和聚合:

select c.class, gs.ts, coalesce(sum(t.count), 0)
from generate_series('2020-05-20 00:00:00'::timestamp, '2020-05-21 23:55:00'::timestamp, interval '5 minute') gs(ts) cross join
     (select distinct class from t) c left join
     t
     on t.timestamp = gs.ts
group by c.class, gs.ts;

我突然想到,时间戳在您的数据中可能不准确。如果是这样的话,用不等式来表示 join :

on t.timestamp >= gs.ts and
        t.timestamp < gs.ts + interval '5 minute'
fiei3ece

fiei3ece2#

假设您的表定义:

create table events(
    class       int,
    ts          timestamp,
    cnt         int
);

示例查询,逐步生成所有内容:

with time_range as (
    select timestamp '2020-05-20 00:00:00' as start_time,   -- current_timestamp - interval '2 day'
           timestamp '2020-05-22 00:00:00' as end_time      -- current_timestamp
),
interested_events as (
    select e.class, e.ts, e.cnt
    from events e
    inner join time_range tr
        on (e.ts >= tr.start_time and e.ts < tr.end_time)
),
classes_having_events as (
    select distinct class
    from interested_events
),
periods as (
    select ts as period_start, ts + interval '5 minute' as period_end
    from generate_series(
        (select start_time from time_range), 
        (select end_time from time_range) - interval '1 second',  
        interval '5 minute') ts 
)
select
    c.class, 
    p.period_start ts,
    (select coalesce(sum(cnt), 0) 
    from interested_events e
    where e.class = c.class
      and e.ts >= p.period_start
      and e.ts < p.period_end) as cnt
from classes_having_events as c
cross join periods as p
order by 2, 1;

在时间范围内,定义应分析的开关事件的时间间隔。
在感兴趣的事件中,根据先前定义的时间间隔(时间范围-开始时间包括在内,结束时间不包括在内)选择事件。
在类中,创建了一组类。包括在所选时间间隔内至少有一个事件的每个类。
在句点中创建了5分钟句点。
最后,我们交叉连接一组带有句点的类,并为每个组合类和句点计算事件数。

相关问题