I have one table called INVENTORY which has data:
x
ITEM_NUM SUB_INV LOT_NUM QUANTITY LOT_EXPIRY_DATE
101 22 A1 10 9/29/2019
101 22 A2 14 9/28/2019
Let’s say, I have a request to fetch the quantity of 20 from these LOTs. As per the table, I have a total quantity available 24 (10 + 14). So I have enough quantity. I can take 10 Quantities from A1 and 10 from A2. But Instead, I have to look at the LOT_EXPIRY_DATE. Since A2 is expiring first, I shall take 14 quantities from A2 and then the rest of the quantities i.e. 6 from A1.
So below query works just fine:
SELECT
lot_num,
item_num,
quantity,
lot_expiry_date,
CASE
WHEN req_quantity >= rolling_qty THEN quantity
ELSE req_quantity - LAG(rolling_qty) OVER(
ORDER BY
lot_expiry_date
)
END AS qty_fetched
FROM
(
WITH base_inv_balance AS (
SELECT
item_num,
lot_num,
quantity,
lot_expiry_date
FROM
inventory
WHERE
item_num = '101'
AND sub_inv = '22'
),requested_transaction AS (
SELECT
'101' AS item_num,
20 AS req_quantity
FROM
dual
)
SELECT
base_inv_balance.item_num,
base_inv_balance.lot_num,
base_inv_balance.quantity,
requested_transaction.req_quantity,
base_inv_balance.lot_expiry_date,
SUM(base_inv_balance.quantity) OVER(
PARTITION BY base_inv_balance.item_num
ORDER BY
base_inv_balance.lot_expiry_date
) AS rolling_qty
FROM
base_inv_balance
JOIN requested_transaction ON base_inv_balance.item_num = requested_transaction.item_num
ORDER BY
base_inv_balance.item_num,
base_inv_balance.lot_expiry_date
)
Result:
LOT_NUM ITEM_NUM QUANTITY LOT_EXPIRY_DATE QTY_FETCHED
A2 101 14 9/28/2019 14
A1 101 10 9/29/2019 6
But if the requested quantity is 13, then the result is
LOT_NUM ITEM_NUM QUANTITY LOT_EXPIRY_DATE QTY_FETCHED
A2 101 14 9/28/2019 null
A1 101 10 9/29/2019 -1
Expected Result:
LOT_NUM ITEM_NUM QUANTITY LOT_EXPIRY_DATE QTY_FETCHED
A2 101 14 9/28/2019 13
A1 101 10 9/29/2019 0
Is it possible to have a single query that can work well with both the quantities?
Need help with that query.
Advertisement
Answer
You want a cumulative sum and them some comparison logic:
select i.*,
(case when running_quantity < 20 then quantity
when running_quantity - quantity < 20 then 20 + quantity - running_quantity
else 0
end) as qty_fetched
from (select i.*
sum(quantity) over (partition by item_num, sub_inv order by lot_expiry_date) as running_quantity
from inventory i
where item_num = 101 and sub_inv = 22
) i;
Here is a db<>fiddle.