I'm using SQL Server 2012 to try and set new forecast targets when the weekly quantity value meets or exceeds the minimum lot quantity. I know this will require a running total and also a way to flag what row the running total will need to be reset on.
Currently trying a recursive solution, but I would be fine with a windowed approach as well. Thanks!
CREATE TABLE dbo.Table_1
(
ITEM_ID nvarchar(20) NOT NULL,
DUE_DATE datetime NOT NULL,
MIN_LOT_SIZE int NOT NULL,
QUANTITY int NOT NULL
)
INSERT INTO dbo.Table_1 (ITEM_ID, DUE_DATE, MIN_LOT_SIZE, QUANTITY)
VALUES
('ITEM_1', '1/4/2021', 460, 102)
,('ITEM_1', '1/11/2021', 460, 101)
,('ITEM_1', '2/8/2021', 460, 100)
,('ITEM_1', '3/8/2021', 460, 101)
,('ITEM_1', '4/5/2021', 460, 141)
,('ITEM_1', '5/10/2021', 460, 142)
,('ITEM_1', '6/7/2021', 460, 142)
,('ITEM_1', '7/5/2021', 460, 142)
,('ITEM_1', '8/2/2021', 460, 142)
,('ITEM_1', '9/6/2021', 460, 142)
,('ITEM_1', '10/4/2021', 460, 142)
,('ITEM_1', '11/1/2021', 460, 142)
,('ITEM_2', '10/4/2021', 5000, 1057)
,('ITEM_2', '11/1/2021', 5000, 1422)
,('ITEM_3', '1/4/2021', 3050, 17)
,('ITEM_3', '1/11/2021', 3050, 761)
,('ITEM_3', '2/1/2021', 3050, 752)
,('ITEM_3', '3/1/2021', 3050, 760)
,('ITEM_3', '4/5/2021', 3050, 1059)
,('ITEM_3', '5/3/2021', 3050, 1066)
,('ITEM_3', '6/7/2021', 3050, 1066)
,('ITEM_3', '7/5/2021', 3050, 1066)
,('ITEM_3', '8/2/2021', 3050, 1061)
,('ITEM_3', '9/6/2021', 3050, 1066)
,('ITEM_3', '10/4/2021', 3050, 1061)
,('ITEM_3', '11/1/2021', 3050, 1066)
My current code below works for ITEM_1 with regards to flagging the correct row, but the subsequent ITEM_1 running total goes into ITEM_2 after the second flag and will be the case going forward for all items.
Query:
WITH cte AS
(
SELECT
rn, item_id, due_date, min_lot_size, quantity, running_total, flag
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY item_id, due_date) AS rn,
item_id,
due_date,
min_lot_size,
quantity,
SUM(quantity) OVER (PARTITION BY item_id ORDER BY due_date ASC, quantity DESC ROWS UNBOUNDED PRECEDING) AS running_total,
CASE
WHEN SUM(quantity) OVER (PARTITION BY item_id ORDER BY due_date ASC, quantity DESC ROWS UNBOUNDED PRECEDING) >= min_lot_size
THEN 1
ELSE 0
END AS flag
FROM
Table_1) A
WHERE
rn = 1
UNION ALL
SELECT
r.rn, r.item_id, r.due_date, r.min_lot_size, r.quantity,
CASE c.flag
WHEN 1 THEN r.quantity
ELSE c.running_total + r.quantity
END,
CASE
WHEN
CASE c.flag
WHEN 1 THEN r.quantity
ELSE c.running_total + r.quantity
END > c.min_lot_size
THEN 1 ELSE 0
END
FROM
cte c
JOIN
(SELECT
ROW_NUMBER() OVER (ORDER BY item_id, due_date) AS rn,
item_id, due_date, min_lot_size, quantity
FROM Table_1) r ON r.rn = c.rn + 1
)
SELECT *
FROM cte
ORDER BY rn
OPTION (maxrecursion 0)
Desired output:
