2016-12-01 77 views
4

我在表中的月份时间序列数据中,日期是月份的最后一天。数据中缺少一些日期。我想插入这些日期并为其他属性设置零值。 表如下:在Postgresql的时间序列数据中添加缺少的每月日期

id  report_date price 
1  2015-01-31 40 
1  2015-02-28 56 
1  2015-04-30 34 
2  2014-05-31 45 
2  2014-08-31 47 

我想这个表转换为

id  report_date price 
1  2015-01-31 40 
1  2015-02-28 56 
1  2015-03-31 0 
1  2015-04-30 34 
2  2014-05-31 45 
2  2014-06-30 0 
2  2014-07-31 0 
2  2014-08-31 47 

有什么办法,我们可以在PostgreSQL做到这一点? 目前我们正在用Python做这件事。由于我们的数据每天都在增长,并且仅仅为了一项任务而无法处理I/O。

谢谢

回答

1

可以使用generate_series()生成日期,然后left join中的值带来做到这一点:

with m as (
     select id, min(report_date) as minrd, max(report_date) as maxrd 
     from t 
     group by id 
    ) 
select m.id, m.report_date, coalesce(t.price, 0) as price 
from (select m.*, generate_series(minrd, maxrd, interval '1' month) as report_date 
     from m 
    ) m left join 
    t 
    on m.report_date = t.report_date; 

编辑:

原来那上面没有相当有效,因为在月末增加月份并不能保持月份的最后一天。

这很容易固定:

with t as (
     select 1 as id, date '2012-01-31' as report_date, 10 as price union all 
     select 1 as id, date '2012-04-30', 20 
    ), m as (
     select id, min(report_date) - interval '1 day' as minrd, max(report_date) - interval '1 day' as maxrd 
     from t 
     group by id 
    ) 
select m.id, m.report_date, coalesce(t.price, 0) as price 
from (select m.*, generate_series(minrd, maxrd, interval '1' month) + interval '1 day' as report_date 
     from m 
    ) m left join 
    t 
    on m.report_date = t.report_date; 

第一CTE只是以产生采样数据。

+0

谢谢戈登! 这对我有用 – liferacer

0

这是对Gordon的查询的轻微改进,它在某些情况下未能获取一个月的最后日期。

基本上你生成minmax日期之间的所有月份结束日期为每个ID(使用generate_series)和left join在此生成的表显示丢失的日期与0价格。

with minmax as (
     select id, min(report_date) as mindt, max(report_date) as maxdt 
     from t 
     group by id 
    ) 
select m.id, m.report_date, coalesce(t.price, 0) as price 
from (select *, 
     generate_series(date_trunc('MONTH',mindt+interval '1' day), 
         date_trunc('MONTH',maxdt+interval '1' day), 
         interval '1' month) - interval '1 day' as report_date 
     from minmax 
    ) m 
left join t on m.report_date = t.report_date 

Sample Demo