在postgresql中按月在两个日期之间生成日期系列并按月平均
Generate date series by month between two dates and avrage by month in postgresql
我想为两个日期之间的每个月创建一行,每个月的第一天应该是开始日期或每个月的第一天,最后一个日期应该是每个月的最后一天每个月或结束日期,我的 table.
的平均值(如果日期开始 = 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
我尝试使用生成系列和日期 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,
(date_trunc('month', '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 '1 MONTH' ):: DATE AS date_start ,
(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', DATE '2020-05-21', 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 直接处理日期,注意日期操作以确保我有第一天和最后一天。然后在任务的外部我选择了那些日期或参数日期或生成的日期(最大和最少的功能),
我想为两个日期之间的每个月创建一行,每个月的第一天应该是开始日期或每个月的第一天,最后一个日期应该是每个月的最后一天每个月或结束日期,我的 table.
的平均值(如果日期开始 = 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
我尝试使用生成系列和日期 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,
(date_trunc('month', '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 '1 MONTH' ):: DATE AS date_start ,
(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', DATE '2020-05-21', 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 直接处理日期,注意日期操作以确保我有第一天和最后一天。然后在任务的外部我选择了那些日期或参数日期或生成的日期(最大和最少的功能),