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
100is 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 forABCI will update the order to new kitABD. - For
102, as order date is15-Oct-24, and on that dateABDtransitions toABE, and since the order was placed forABC, we will consider the previous transition ofABCtoABD. Hence the order will be placed forABEinstead 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.kitreally relevant when findingnew_kit? It seems like this is always just the row whereorder_date BETWEEN valid_from AND valid_to.orderstable is not part of thekit_transition_mappingtable based on theorder_date, then the component breakdown should be done using thekit_componenttable. I updated the question with my attempt, but the order 102 and 103 are not transitioning correctly.