In Oracle SQL, I have a product transition table named kit_transition_mapping
that is a slowly changing dimension and an orders
table. For an order_no
based on the order_date
, I need to utilize the kit_transition_mapping
table to get to the right kit.
For e.g.,
- order
100
is placed on15-Aug-24
. As there is no kit transition happening on that date forABC
, I will utilize the original kitABC
. - For
101
, since the order date is between the transition date forABC
I will update the order to new kitABD
. - For
102
, as order date is15-Oct-24
, and on that dateABD
transitions toABE
, and since the order was placed forABC
, we will consider the previous transition ofABC
toABD
. Hence the order will be placed forABE
instead ofABC
.
Given the above scenario and the kit_component
table that breaks down a kit to the component
level. How to write a query to get the expected result?
kit_transition_mapping
old_kit | new_kit | valid_from | valid_to |
---|---|---|---|
ABC | ABD | 01-Sep-24 | 30-Sep-24 |
ABD | ABE | 01-Oct-24 | 31-Oct-24 |
ABE | ABF | 01-Nov-24 | 30-Nov-24 |
orders
order_no | kit | order_date | qty |
---|---|---|---|
100 | ABC | 15-Aug-24 | 1 |
101 | ABC | 15-Sep-24 | 1 |
102 | ABC | 15-Oct-24 | 1 |
103 | ABC | 15-Nov-24 | 1 |
104 | ABD | 15-Oct-24 | 1 |
105 | ABE | 15-Nov-24 | 1 |
106 | ABE | 15-Oct-24 | 1 |
107 | DEX | 01-Dec-24 | 1 |
kit_component
kit | comp | qty |
---|---|---|
ABC | A | 1 |
ABC | B | 2 |
ABC | C | 3 |
ABD | A | 1 |
ABD | B | 2 |
ABD | D | 4 |
ABE | A | 1 |
ABE | B | 2 |
ABE | E | 5 |
ABF | A | 1 |
ABF | B | 2 |
ABF | F | 6 |
DEX | D | 2 |
DEX | E | 3 |
DEX | X | 4 |
expected_result
order_no | order_date | original_kit | new_kit | order_qty | comp | comp_qty |
---|---|---|---|---|---|---|
100 | 15-Aug-24 | ABC | ABC | 1 | A | 1 |
100 | 15-Aug-24 | ABC | ABC | 1 | B | 2 |
100 | 15-Aug-24 | ABC | ABC | 1 | C | 3 |
101 | 15-Sep-24 | ABC | ABD | 1 | A | 1 |
101 | 15-Sep-24 | ABC | ABD | 1 | B | 2 |
101 | 15-Sep-24 | ABC | ABD | 1 | D | 4 |
102 | 15-Oct-24 | ABC | ABE | 1 | A | 1 |
102 | 15-Oct-24 | ABC | ABE | 1 | B | 2 |
102 | 15-Oct-24 | ABC | ABE | 1 | E | 5 |
103 | 15-Nov-24 | ABC | ABF | 1 | A | 1 |
103 | 15-Nov-24 | ABC | ABF | 1 | B | 2 |
103 | 15-Nov-24 | ABC | ABF | 1 | F | 6 |
104 | 15-Oct-24 | ABD | ABE | 1 | A | 1 |
104 | 15-Oct-24 | ABD | ABE | 1 | B | 2 |
104 | 15-Oct-24 | ABD | ABE | 1 | E | 5 |
105 | 15-Nov-24 | ABE | ABF | 1 | A | 1 |
105 | 15-Nov-24 | ABE | ABF | 1 | B | 2 |
105 | 15-Nov-24 | ABE | ABF | 1 | F | 6 |
106 | 15-Oct-24 | ABE | ABE | 1 | A | 1 |
106 | 15-Oct-24 | ABE | ABE | 1 | B | 2 |
106 | 15-Oct-24 | ABE | ABE | 1 | E | 5 |
107 | 01-Dec-24 | DEX | DEX | 1 | D | 2 |
107 | 01-Dec-24 | DEX | DEX | 1 | E | 3 |
107 | 01-Dec-24 | DEX | DEX | 1 | X | 4 |
Here is the CTEs for the above data:
WITH orders (order_no, kit, order_date, qty) AS (
SELECT 100, 'ABC', DATE '2024-08-15', 1 FROM DUAL UNION ALL
SELECT 101, 'ABC', DATE '2024-09-15', 1 FROM DUAL UNION ALL
SELECT 102, 'ABC', DATE '2024-10-15', 1 FROM DUAL UNION ALL
SELECT 103, 'ABC', DATE '2024-11-15', 1 FROM DUAL UNION ALL
SELECT 104, 'ABD', DATE '2024-10-15', 1 FROM DUAL UNION ALL
SELECT 105, 'ABE', DATE '2024-11-15', 1 FROM DUAL UNION ALL
SELECT 106, 'ABE', DATE '2024-10-15', 1 FROM DUAL UNION ALL
SELECT 107, 'DEX', DATE '2024-12-01', 1 FROM DUAL
),
kit_transition_mapping (old_kit, new_kit, valid_from, valid_to) AS (
SELECT 'ABC', 'ABD', DATE '2024-09-01', DATE '2024-09-30' FROM DUAL UNION ALL
SELECT 'ABD', 'ABE', DATE '2024-10-01', DATE '2024-10-31' FROM DUAL UNION ALL
SELECT 'ABE', 'ABF', DATE '2024-11-01', DATE '2024-11-30' FROM DUAL
),
kit_component (kit, comp, qty) AS (
SELECT 'ABC', 'A', 1 FROM DUAL UNION ALL
SELECT 'ABC', 'B', 2 FROM DUAL UNION ALL
SELECT 'ABC', 'C', 3 FROM DUAL UNION ALL
SELECT 'ABD', 'A', 1 FROM DUAL UNION ALL
SELECT 'ABD', 'B', 2 FROM DUAL UNION ALL
SELECT 'ABD', 'D', 4 FROM DUAL UNION ALL
SELECT 'ABE', 'A', 1 FROM DUAL UNION ALL
SELECT 'ABE', 'B', 2 FROM DUAL UNION ALL
SELECT 'ABE', 'E', 5 FROM DUAL UNION ALL
SELECT 'ABF', 'A', 1 FROM DUAL UNION ALL
SELECT 'ABF', 'B', 2 FROM DUAL UNION ALL
SELECT 'ABF', 'F', 6 FROM DUAL UNION ALL
SELECT 'DEX', 'D', 2 FROM DUAL UNION ALL
SELECT 'DEX', 'E', 3 FROM DUAL UNION ALL
SELECT 'DEX', 'X', 4 FROM DUAL
),
kit_resolution (order_no, original_kit, kit, order_date, order_qty) AS (
SELECT ho.order_no, ho.kit AS original_kit, ho.kit, ho.order_date, ho.qty AS order_qty
FROM orders ho
UNION ALL
SELECT kr.order_no, kr.original_kit, km.new_kit, kr.order_date, kr.order_qty
FROM kit_resolution kr
JOIN kit_transition_mapping km ON kr.kit = km.old_kit AND kr.order_date BETWEEN km.valid_from AND km.valid_to
)
SELECT
kr.order_no,
TO_CHAR(kr.order_date, 'DD-Mon-YY') AS order_date,
kr.original_kit,
kr.kit AS new_kit,
kr.order_qty,
kc.comp,
kc.qty * kr.order_qty AS comp_qty
FROM kit_resolution kr
JOIN kit_component kc ON kr.kit = kc.kit
WHERE NOT EXISTS (
SELECT 1 FROM kit_transition_mapping km
WHERE kr.kit = km.old_kit AND kr.order_date BETWEEN km.valid_from AND km.valid_to
)
ORDER BY kr.order_no, kc.comp;
orders.kit
really relevant when findingnew_kit
? It seems like this is always just the row whereorder_date BETWEEN valid_from AND valid_to
.orders
table is not part of thekit_transition_mapping
table based on theorder_date
, then the component breakdown should be done using thekit_component
table. I updated the question with my attempt, but the order 102 and 103 are not transitioning correctly.