Reputation: 35
In desperate need of help from all Oracle SQL guru's. Need to generate output for effective and discontinue dates factoring in 2 other dates namely promo_prep date and promo_start date.
I need to check if promo_prep is greater than eff and less DISC. If it is then become the new disc and the new eff for the next row. Up until the promostart date, so if eff and disc changes happen between promo dates they should remain. Only when promo dates fall between EFF and DISC do they need to be applied and create a new record. Images shown below. Appreaciate any help with this query.
Thank you
Table view before transformation
Desired Ouput
DDL
CREATE TABLE TEST1
( item varchar2(20),
loc varchar2(20),
qty number,
eff date,
disc date,
promo_prep date,
promostart date
);
--
Insert into TEST1
(ITEM, LOC, QTY, EFF, DISC,
PROMO_PREP, PROMOSTART)
Values
('item1', 'loc1', 280, TO_DATE('11/29/2022', 'MM/DD/YYYY'), TO_DATE('1/10/2023', 'MM/DD/YYYY'),
TO_DATE('1/8/2023', 'MM/DD/YYYY'), TO_DATE('1/16/2023', 'MM/DD/YYYY'));
Insert into TEST1
(ITEM, LOC, QTY, EFF, DISC,
PROMO_PREP, PROMOSTART)
Values
('item1', 'loc1', 300, TO_DATE('1/10/2023', 'MM/DD/YYYY'), TO_DATE('1/14/2023', 'MM/DD/YYYY'),
TO_DATE('1/8/2023', 'MM/DD/YYYY'), TO_DATE('1/16/2023', 'MM/DD/YYYY'));
Insert into TEST1
(ITEM, LOC, QTY, EFF, DISC,
PROMO_PREP, PROMOSTART)
Values
('item1', 'loc1', 310, TO_DATE('1/14/2023', 'MM/DD/YYYY'), TO_DATE('1/1/2999', 'MM/DD/YYYY'),
TO_DATE('1/8/2023', 'MM/DD/YYYY'), TO_DATE('1/16/2023', 'MM/DD/YYYY'));
COMMIT;
Upvotes: 0
Views: 48
Reputation: 6750
You may generate three possible pairs of effective and discontinue dates for each row and then unpivot the result:
with prep as ( select item, loc, qty, eff as eff1, least(disc, promo_prep) as disc1, least(disc, promo_prep) as eff2, least(disc, promostart) as disc2, least(disc, promostart) as eff3, disc as disc3 from test1 ) select * from prep unpivot ( (eff, disc) for type_ in ( (eff1, disc1) as 'before_promo', (eff2, disc2) as 'promo', (eff3, disc3) as 'after_promo' ) ) /*Include only valid combin*/ where eff < disc
ITEM | LOC | QTY | TYPE_ | EFF | DISC |
---|---|---|---|---|---|
item1 | loc1 | 280 | before_promo | 2022-11-29 | 2023-01-08 |
item1 | loc1 | 280 | promo | 2023-01-08 | 2023-01-10 |
item1 | loc1 | 300 | promo | 2023-01-08 | 2023-01-14 |
item1 | loc1 | 310 | promo | 2023-01-08 | 2023-01-16 |
item1 | loc1 | 310 | after_promo | 2023-01-16 | 2999-01-01 |
See SQL fiddle
UPD: If it is possible to have non-overlapping intervals, then you need to check this condition before date calculation. Below is updated script.
with prep as ( select item, loc, qty, case when promo_prep < disc and promostart > eff then eff end as eff1, case when promo_prep < disc and promostart > eff then least(disc, promo_prep) end as disc1, case when promo_prep < disc and promostart > eff then least(disc, promo_prep) end as eff2, case when promo_prep < disc and promostart > eff then least(disc, promostart) end as disc2, case when promo_prep < disc and promostart > eff then least(disc, promostart) end as eff3, case when promo_prep < disc and promostart > eff then disc end as disc3, case when promo_prep >= disc or promo_prep is null or promostart <= eff or promostart is null then eff end as eff4, case when promo_prep >= disc or promo_prep is null or promostart <= eff or promostart is null then disc end as disc4 from test1 ) select * from prep unpivot ( (eff, disc) for type_ in ( (eff1, disc1) as 'before_promo', (eff2, disc2) as 'promo', (eff3, disc3) as 'after_promo', (eff4, disc4) as 'no_promo' ) ) /*Include only valid combinations*/ where eff < disc
which for this sample data
ITEM | LOC | QTY | EFF | DISC | PROMO_PREP | PROMOSTART |
---|---|---|---|---|---|---|
item4 | loc4 | 280 | 2022-11-29 | 2023-01-10 | 2023-01-08 | 2023-01-09 |
item4 | loc4 | 300 | 2023-01-10 | 2023-01-14 | 2023-01-10 | 2023-01-25 |
item4 | loc4 | 310 | 2023-01-14 | 2023-01-25 | 2023-01-10 | 2023-01-25 |
item4 | loc4 | 311 | 2023-01-25 | 2023-10-01 | 2023-01-10 | 2023-01-25 |
item4 | loc4 | 312 | 2023-10-01 | 2999-01-01 | 2023-01-10 | 2023-01-25 |
returns this output
ITEM | LOC | QTY | TYPE_ | EFF | DISC |
---|---|---|---|---|---|
item4 | loc4 | 280 | before_promo | 2022-11-29 | 2023-01-08 |
item4 | loc4 | 280 | promo | 2023-01-08 | 2023-01-09 |
item4 | loc4 | 280 | after_promo | 2023-01-09 | 2023-01-10 |
item4 | loc4 | 300 | promo | 2023-01-10 | 2023-01-14 |
item4 | loc4 | 310 | promo | 2023-01-10 | 2023-01-25 |
item4 | loc4 | 311 | no_promo | 2023-01-25 | 2023-10-01 |
item4 | loc4 | 312 | no_promo | 2023-10-01 | 2999-01-01 |
Upvotes: 1
Reputation: 954
You can do this pretty straightforwardly by just appending a row when promo_prep
is between the eff
and disc
dates
select
item,
loc,
qty,
eff,
case
when promo_prep between eff and disc then promo_prep
else disc
end as disc
from test1
union all
select
item,
loc,
qty,
promo_prep as eff,
disc
from test1
where
promo_prep between eff and disc
ITEM | LOC | QTY | EFF | DISC |
---|---|---|---|---|
item1 | loc1 | 280 | 2022-11-29T00:00:00Z | 2023-01-08T00:00:00Z |
item1 | loc1 | 300 | 2023-01-10T00:00:00Z | 2023-01-14T00:00:00Z |
item1 | loc1 | 310 | 2023-01-14T00:00:00Z | 2999-01-01T00:00:00Z |
item1 | loc1 | 280 | 2023-01-08T00:00:00Z | 2023-01-10T00:00:00Z |
Upvotes: 0