Here is the function:
CREATE FUNCTION dbo.agedItemResult(@ILC VARCHAR(30))
RETURNS @AgedTable TABLE (
ItemID INT,
ItemLookupCode VARCHAR(30),
[Month] INT,
[Year] INT,
Aged INT,
Debug01 VARCHAR(MAX),
Debug02 VARCHAR(MAX),
Debug03 VARCHAR(MAX),
Debug04 VARCHAR(MAX),
Debug05 VARCHAR(MAX)
)
AS
BEGIN
DECLARE @TotalSold INT
DECLARE @AdjustmentQty INT
DECLARE @FirstRcvdStart DATETIME
DECLARE @FirstRcvdEnd DATETIME
--DECLARE @ILC VARCHAR(MAX)
--DECLARE @ItemID INT
DECLARE @MovingQty INT
DECLARE @MovingMonthStart DATETIME
DECLARE @MovingMonthEnd DATETIME
DECLARE @CurrentMonthStart DATETIME
DECLARE @CurrentMonthEnd DATETIME
DECLARE @CurrentRcvd INT
DECLARE @NumMonths INT
DECLARE @AgeReached INT
/*DECLARE @AgedTable TABLE ( ItemID INT,
ItemLookupCode VARCHAR(MAX),
[Month] INT,
[Year] INT,
Aged INT,
Debug01 VARCHAR(MAX),
Debug02 VARCHAR(MAX),
Debug03 VARCHAR(MAX),
Debug04 VARCHAR(MAX),
Debug05 VARCHAR(MAX)
)*/
--SET @ILC = '21208641'
SET @TotalSold = (SELECT SUM(Sold) FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC)
SET @AdjustmentQty = (SELECT SUM(HQAdjustment) FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC)
SET @FirstRcvdStart = (SELECT TOP 1 FirstTransferred FROM JSInventorySnapShot ORDER BY FirstTransferred ASC)
SET @FirstRcvdEnd = (SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, @FirstRcvdStart)+1,0)))
SET @CurrentMonthStart = (SELECT DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0, GETDATE()),0)))
SET @CurrentMonthEnd = (SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, GETDATE())+1,0)))
SET @NumMonths = (SELECT CASE
WHEN DATEPART(DAY, @FirstRcvdStart) > DATEPART(DAY, @CurrentMonthEnd)
THEN DATEDIFF(MONTH, @FirstRcvdStart, @CurrentMonthEnd) - 1
ELSE DATEDIFF(MONTH, @FirstRcvdStart, @CurrentMonthEnd)
END) + 1
SET @MovingQty = @TotalSold
SET @CurrentRcvd = ISNULL((SELECT SUM(Rcvd) FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC AND [Month] = Month(@FirstRcvdStart)), 0) + @AdjustmentQty
SET @MovingMonthStart = @FirstRcvdStart
SET @MovingMonthEnd = @FirstRcvdEnd
SET @MovingQty = @MovingQty - @CurrentRcvd
SET @AgeReached = 0
WHILE(@NumMonths > 0)
BEGIN
IF (@CurrentRcvd = 0)
BEGIN
INSERT INTO @AgedTable (ItemID, ItemLookupCode, [Month], [Year], Aged, Debug01)
SELECT (SELECT TOP 1 ItemID FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC),
@ILC,
MONTH(@MovingMonthStart),
YEAR(@MovingMonthStart),
0,
@AdjustmentQty
END
ELSE
BEGIN
IF(@MovingQty > 0)
BEGIN
INSERT INTO @AgedTable (ItemID, ItemLookupCode, [Month], [Year], Aged, Debug01)
SELECT (SELECT TOP 1 ItemID FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC),
@ILC,
MONTH(@MovingMonthStart),
YEAR(@MovingMonthStart),
0,
@AdjustmentQty
END
ELSE
BEGIN
IF (@AgeReached = 1)
BEGIN
INSERT INTO @AgedTable (ItemID, ItemLookupCode, [Month], [Year], Aged)
SELECT (SELECT TOP 1 ItemID FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC),
@ILC,
MONTH(@MovingMonthStart),
YEAR(@MovingMonthStart),
@CurrentRcvd
END
ELSE
BEGIN
INSERT INTO @AgedTable (ItemID, ItemLookupCode, [Month], [Year], Aged)
SELECT (SELECT TOP 1 ItemID FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC),
@ILC,
MONTH(@MovingMonthStart),
YEAR(@MovingMonthStart),
(-1 * @MovingQty)
SET @AgeReached = 1
END
END
END
SET @NumMonths = @NumMonths - 1
SET @MovingMonthStart = (SELECT DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0, @MovingMonthStart)+1,0)))
SET @MovingMonthEnd = (SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, @MovingMonthEnd)+2,0)))
SET @CurrentRcvd = ISNULL((SELECT SUM(Rcvd) FROM JSInventorySnapShot WHERE ItemLookupCode = @ILC AND [Month] = Month(@MovingMonthStart)), 0)
SET @MovingQty = @MovingQty - @CurrentRcvd
END
RETURN
END
Here's what it does in a nutshell:
First we find the first item ever received or moved and use the date as the starting date. Then we find the total sales for the that item, and begin subtracting the receiving amount from sales. The remainder is considered aged (not sold) and is evaluated against the next month. We then move to the next month and repeat the process until we hit a negative number or 0. If we hit a negative number then that means we have hit a month that we ordered more than sold to date, and that amount is considered aged (not sold). If there are more months to evaluate then any FURTHER received amount is considered aged by default as it clearly as not been sold.
Here is sample data from the table used for evaluation:
ID ItemID ItemLookupCode HQAdjustment FirstTransferred Rcvd RcvdDateEarly RcvdDateLate Sold SoldDateEarly SoldDateLate Sales Month Year StartOfMonthQty EndOfMonthQty
17350 188993 21208641 0 2012-04-05 13:29:14.000 48 2012-04-27 11:00:40.100 2012-04-27 11:00:40.100 40 2012-04-05 13:29:14.000 2012-04-30 12:50:13.000 75.20 4 2012 0 8
34427 188993 21208641 0 2012-04-05 13:29:14.000 120 2012-05-22 10:14:40.213 2012-05-22 10:14:40.213 24 2012-05-04 17:42:12.000 2012-05-29 10:22:10.000 44.72 5 2012 8 104
48437 188993 21208641 0 2012-04-05 13:29:14.000 0 NULL NULL 12 2012-06-02 16:24:45.000 2012-06-21 11:15:05.000 22.36 6 2012 104 92
62369 188993 21208641 0 2012-04-05 13:29:14.000 60 2012-07-16 12:57:33.330 2012-07-16 12:57:33.330 9 2012-07-11 14:42:01.000 2012-07-25 14:58:41.000 16.22 7 2012 92 143
75781 188993 21208641 0 2012-04-05 13:29:14.000 0 NULL NULL 2 2012-08-01 12:56:10.000 2012-08-14 19:01:00.000 4.01 8 2012 143 141
Here is the result of my function for the above data:
ItemLookupCode Month Rcvd Sold Aged
21208641 4 48 40 0
21208641 5 120 24 81
21208641 6 0 12 0
21208641 7 60 9 60
21208641 8 0 2 0
This tells me that we sold everything received in April. Ordered again in May, sold some but still have left over inventory (aged). Then without selling the inventory out in July we ordered more again, and therefore that inventory is automatically considered to be aged.
The purpose of this function is stop what happened above. Which is ordering items that have aged (unsold) inventory. It's also used for evaluating how much of a department is aged and if we should consider starting a sale to get rid of aged items.
The problem is that we have no less then 40,000 items to evaluate. This function works great for single items, however it takes 30 seconds for 100 items. I'm hoping someone can come a long and look at my function and realize I'm going about it the completely wrong way. If I could accomplish inline calculations and carry over the remainder that would be great.
I basically need this in simplified pseudo-code:
Foreach (Month2Date)
If AllInventoryAged = 1 Then //This says we've reached our sales:rcved thresh-hold and all received inventory is aged from here on out.
ThisMonthAged = RcvedForMonth
Else
TotalSales - RcvedForMonth = Aged
If Aged < 0 Then
ThisMonthAged = Aged * -1 //We received more than sold so it's negative and we have hit our sales:rcved thresh-hold.
AllInventoryAged = 1 //Anything received from this point on is aged.
Else
ThisMonthAged = 0 //We received less this month then sold. A good thing.
TotalSales = Aged //We carry on the remainder for further evaluation
I hope I have been thorough in explaining myself this time. Sorry it's so long. I just really wanted to cover all questions I had in my last post.