Oracle version: 12c.
I have the below table:
CAT_PROD FROM_DT TO_DT IMP
A1 15/01/2023 07/02/2023 100
A2 13/01/2023 16/01/2023 100
And I would like to create the below output:
CAT_PROD RANGE_DT IMP_RANGE EXPLANATION
A1 202301 70,83 There are 17 days between 15th Jan (included) and 31st Jan. 17*100/24 = 70.83. 24 is the number of days between 15th Jan and 7th Feb.
A1 202302 29,17 There are 7 days between 1st Feb (included) and 7th Feb. 7*100/24 = 29.17. 24 is the number of days between 15th Jan and 7th Feb.
A2 202301 100 There are 4 days between 13th Jan (included) and 16th Jan. 4*100/4= 100. 4 is the number of days between 13th Jan and 16th Jan.
Criteria:
- IMP is prorated amongs the days of the month in which it falls.
- RANGE_DT is the YYYYMM for each combination of days in the month.
- The combination CAT_PROD and RANGE_DT should be unique.
EDIT: This is what I have tried, but it is very very slow when having more than a few rows in the original data.
WITH aux(cat_prod, startdate, enddate, imp) AS
(SELECT 'A1' , DATE'2023-01-15' , DATE'2023-02-07' , 100 from dual
UNION
SELECT 'A2' , DATE'2023-01-13' , DATE'2023-01-16' , 100 from dual
),
apply_cross as
(select e.cat_prod,
e.imp,
enddate-startdate + 1 total_days_range,
case
when e.startdate > x.s_date
then e.startdate
else x.s_date
end as start_date,
case
when e.enddate < x.e_date
then e.enddate
else x.e_date
end as end_date
from aux e cross apply
(select trunc( e.startdate, 'mm') + (level-1) * interval '1' month as s_date,
trunc( e.startdate + (level) * interval '1' month, 'mm') -1 as e_date
from dual
connect by level <= months_between( trunc( e.enddate, 'mm'),trunc( e.startdate, 'mm')) + 1
) x
)
select ac.cat_prod,
to_char(start_date, 'YYYYMM') month_id,
round(imp*(end_date-start_date+1)/total_days_range, 2) imp_prorate
from apply_cross ac;