在PostgreSQL中按月生成日期系列,按月生成平均值

问题描述

我想为两个日期之间的每个月创建一行,每个月的第一天应该是开始日期或每个月的第一天,最后一个日期应该是每个月的最后一天或结束日期,并带有我表格的平均值(如果日期开始= 15,则平均值应为15/30)。

输入:

product_id | date_start | date_end
1          | 16-01-2020 | 15-03-2020
2          | 07-01-2020 | 22-04-2020

结果应为:

product_id | date_start | date_end    | average
1          | 16-01-2020 | 31-01-2020  | 0.5
1          | 01-02-2020 | 29-02-2020  | 1
1          | 01-03-2020 | 15-03-2020  | 0.5
2          | 07-01-2020 | 31-01-2020  | 0.76  -- (30-07)/30
2          | 01-02-2020 | 29-02-2020  | 1
2          | 01-03-2020 | 31-03-2020  | 1
2          | 01-04-2020 | 22-04-2020  | 0.76

我尝试使用generate series,date trunc和union

SELECT (date_trunc('month',dt) + INTERVAL '1 MONTH' ):: DATE AS date_start,(date_trunc('month',dt) + INTERVAL '2 MONTH - 1 day' ):: DATE AS date_end

FROM generate_series( DATE '2020-01-15',DATE '2020-05-21',interval '1 MONTH' ) AS dt
union select '2020-01-15' as date_start,'2020-01-15'::date) + INTERVAL '1 MONTH - 1 day' ):: DATE AS date_end

union select (date_trunc('month','2020-05-21'::date) ):: DATE AS date_start,'2020-05-21' AS date_end
order by date_start

要求平均值,我要计算两个日期之间的差值

SELECT (date_trunc('month',dt) + INTERVAL '2 MONTH - 1 day' ):: DATE AS date_end,((date_trunc('month',dt) + INTERVAL '2 MONTH - 1 day' ) - (date_trunc('month',dt) + INTERVAL '1 MONTH' ):: DATE )
FROM generate_series( DATE '2020-01-15',interval '1 MONTH' ) AS dt

有了这个,我好像被撞到了墙。

解决方法

以下给出的结果与您期望的大致相同,只有平均值出现偏差。我认为这是由于您的计算不一致而导致的,其中某些日期包含在内,而其他日期则排除了开始日期或结束日期,而我却包含了所有日期。另一个差异是我使用分母计算的当月实际天数而不是30。2月份的平均值必须为1,否则最大值为0.97,而有31天的整月平均值为1.03

with product_dates(product_id,date_start,date_end) as  
     ( values (1,'2020-01-16'::date,'2020-03-15'::date),(2,'2020-01-07'::date,'2020-04-22'::date)
     ) 
select product_id,start_date,end_date,round((end_date-start_date+1 ) * 1.0 / (eom-som+1),2) average   
 from (select product_id,greatest(date_start,dt::date) start_date,least(date_end,(dt+interval '1 month' -interval '1 day')::date) end_date,dt::date som,(dt+interval '1 month' -interval '1 day')::date eom     
       from product_dates 
       cross join generate_series(date_trunc('month',date_start),date_trunc('month',date_end) + interval '1 month' - interval '1 day',interval '1 month'
                                 ) gs(dt)
      ) s1;

心脏是直接处理日期的generate_series,请注意日期操作以确保我有每月的第一天和最后一天。然后在任务的外部,我选择了那些日期或参数date或生成的日期(最大和最小函数),

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...