Это один из немногих случаев, когда я бы рекомендовал решение на основе курсора. Он плохо масштабируется, поэтому, если ваши данные большие, это плохой выбор, но, по крайней мере, он будет делать то, что вам нужно, вполне понятным способом
DECLARE @qoh INT = 95
, @ss INT = 58
, @eoq INT = 96;
CREATE TABLE #data
(
PartId INT
, SalesOrderQty INT
, SalesDate DATE
);
INSERT INTO #data (PartId
, SalesOrderQty
, SalesDate)
VALUES (1, 75, '20190101')
, (1, 100, '20190201')
, (1, 115, '20190301')
, (1, 95, '20190401')
, (1, 132, '20190501');
;with cteOrdered as (
SELECT *, ROW_NUMBER() OVER (PARTITION BY PartID ORDER BY SalesDate) as RowNum
FROM #data
)
SELECT *, @QOH-@SS-SalesOrderQty as Supply, 1 as EOQMultiplier, @QOH as RecommendedQty
INTO #DataTemp
FROM cteOrdered
DECLARE @PartId INT
DECLARE @SalesOrderQty int
DECLARE @SalesDate DATE
DECLARE @RowNum int
DECLARE @Supply int
DECLARE @EOQMultiplier int
DECLARE @RecommendedQty int
DECLARE @PrevRecQty int
DECLARE curMonth CURSOR FOR
SELECT PartId , SalesOrderQty , SalesDate , RowNum , Supply , EOQMultiplier, RecommendedQty
FROM #DataTemp
ORDER BY PartID, RowNum;
OPEN curMonth
FETCH NEXT FROM curMonth
INTO @PartId , @SalesOrderQty , @SalesDate , @RowNum , @Supply , @EOQMultiplier, @RecommendedQty
WHILE @@FETCH_STATUS = 0
BEGIN
IF (@RowNum = 1) BEGIN --No prior month
SET @Supply = @QOH - @SS - @SalesOrderQty
END ELSE BEGIN
SET @Supply = @PrevRecQty - @SalesOrderQty
END
SET @EOQMultiplier = CEILING(ABS(@Supply*1.0/@eoq))
if (@Supply <= 0) BEGIN
SET @RecommendedQty = @EOQMultiplier * @eoq
END ELSE BEGIN
SET @RecommendedQty = @Supply
END
SET @PrevRecQty = @RecommendedQty
UPDATE #DataTemp
SET Supply = @Supply, EOQMultiplier = @EOQMultiplier, RecommendedQty= @RecommendedQty
WHERE PartId = @PartId AND RowNum = @RowNum
FETCH NEXT FROM curMonth
INTO @PartId , @SalesOrderQty , @SalesDate , @RowNum , @Supply , @EOQMultiplier, @RecommendedQty
END
CLOSE curMonth;
DEALLOCATE curMonth;
SELECT * FROM #DataTemp
DROP TABLE #data
DROP TABLE #DataTemp