Monty
3/26/2007 10:11:00 PM
Hi Tom,
First off, thank you, I appreciate your generosity with your code.
For some reason I have an aversion to triggers and also computed columns, so
I was hoping to be able to do it with a view and a stored procedure, but
maybe I need to rethink my position. I will give it a try.
Thanks again.
"Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
news:%23eau299bHHA.1148@TK2MSFTNGP02.phx.gbl...
> Hi Monty,
>
> Here is a trigger that I think does most of what you want. It has some
> limitations. It doesn't have much error checking and you should add that
> for a production system. It needs a new column in your table named
> QtyRemaining which has the remaining quantity available to be shipped for
> each reciept. Note that a normal form purist will object to this since it
> is a value that could be calculated from other data in the table. Also,
> the trigger enforces that only one row is inserted into the table at a
> time and that the inventory cannot go negative. Finally, it assumes that
> all of the inventory transactions are ordered by ID, not by the Date and
> that ID is unique. You will have to decide if these are "features" or
> "bugs". But, hopefully, it gives you a starting place.
>
> CREATE TRIGGER trItemTranx ON [dbo].[ItemTranx]
> FOR INSERT AS
> DECLARE @ID int,
> @ItemID int,
> @Quantity int,
> @QtyRemaining int,
> @FirstAvailableID int,
> @LastRequiredID int,
> @AmountPerUnit decimal(18,2)
> -- Only one row can be inserted at a time
> IF @@RowCount <> 1
> BEGIN
> ROLLBACK
> RAISERROR ('Only 1 row may be inserted into ItemTranx at a time', 16, 1)
> RETURN
> END
> -- Get data from inserted row
> SELECT @ID = ID, @ItemID = ItemID, @Quantity = Quantity
> FROM INSERTED
> -- update QtyRemaining column
> UPDATE [dbo].[ItemTranx] SET QtyRemaining =
> CASE WHEN @Quantity > 0 THEN @Quantity ELSE 0 END
> WHERE [dbo].[ItemTranx].ID = @ID
> IF @Quantity < 0
> -- Compute cost for sales/negative adjustments
> BEGIN
> SET @Quantity = Abs(@Quantity)
> -- Find first and last reciept needed to satisy this amount
> SELECT @FirstAvailableID = Min(t.ID)
> FROM [dbo].[ItemTranx] t
> WHERE t.ItemID = @ItemID AND t.QtyRemaining > 0
> SELECT @LastRequiredID = Min(t.ID)
> FROM [dbo].[ItemTranx] t
> WHERE t.ItemID = @ItemID AND t.ID >= @FirstAvailableID
> AND @Quantity <= (Select Sum (t1.QtyRemaining)
> FROM [dbo].[ItemTranx] t1
> WHERE t1.ItemID = @ItemID AND t1.ID >= @FirstAvailableID
> AND t1.ID <= t.ID)
> -- If can't find a last row, there is not enough inventory for this
> request
> IF @LastRequiredID IS NULL
> BEGIN
> ROLLBACK
> RAISERROR ('Inventory cant go negative', 16, 1)
> RETURN
> END
> -- Determine quantity that will be remaining from last reciept used for
> this sale
> SELECT @QtyRemaining = Sum (t.QtyRemaining) - @Quantity
> FROM [dbo].[ItemTranx] t
> WHERE t.ItemID = @ItemID AND t.ID BETWEEN @FirstAvailableID AND
> @LastRequiredID
> -- Determine cost for this sale
> SELECT @AmountPerUnit =
> (Sum ((CASE WHEN t.ID = @LastRequiredID THEN t.QtyRemaining -
> @QtyRemaining ELSE t.QtyRemaining END)
> * t.AmountPerUnit)) / @Quantity
> FROM [dbo].[ItemTranx] t
> WHERE t.ItemID = @ItemID AND t.ID BETWEEN @FirstAvailableID AND
> @LastRequiredID
> -- Update qtyremaining for all reciepts used for this sale
> -- Note that all but last row must have 0 remaining
> UPDATE t SET QtyRemaining =
> CASE WHEN t.ID = @LastRequiredID THEN @QtyRemaining ELSE 0 END
> FROM [dbo].[ItemTranx] t
> WHERE t.ItemID = @ItemID AND t.ID BETWEEN @FirstAvailableID AND
> @LastRequiredID
> -- Update cost for this sale
> UPDATE t SET t.AmountPerUnit = @AmountPerUnit
> FROM [dbo].[ItemTranx] t
> WHERE t.ID = @ID
> END
> go
>
> Good luck,
> Tom
>
> "Monty" <monty@community.nospam> wrote in message
> news:%23xZurs8bHHA.2088@TK2MSFTNGP05.phx.gbl...
>> Just to simplify this, ignore the question about the negative inventory
>> for now. I think I've found a relatively elegant solution to prevent that
>> situation from happening. So, my question is, "Referring to my sample
>> table and data, how can I calculate the FIFO cost for the outgoing items
>> in rows 3,6 and 7?" Please ignore Rows 8 and 9 from the sample above.
>>
>> Here is my DDL and Sample Data, updated and with reformatted comments for
>> easier use:
>>
>> CREATE TABLE [dbo].[ItemTranx] (
>> [ID] [int] NOT NULL , /*this is an identity col but I removed it for
>> this
>> demo so i can specify the row values*/
>> [ItemID] [int] NOT NULL , /*FK to Items table (for this sample they are
>> all the same item type) */
>> [TransactionType] [smallint] NOT
>> NULL, /* 1=Received(+),2=Adjustment(+/-),3=Sold(-) */
>> [Quantity] [decimal](18, 2) NOT NULL, /* positive for items received,
>> negative for outgoing */
>> [AmountPerUnit] [decimal](18, 2) NULL, /* actual cost for incoming items,
>> FIFO for outgoing */
>> [Date] [smalldatetime] NOT NULL,
>> [Comment] [nvarchar] (200) /* just for clarity with this example */
>> ) ON [PRIMARY]
>>
>> INSERT INTO [dbo].[ItemTranx] VALUES (1,1,1,50,12,'01-JAN-2007','+50 @
>> $12')
>> INSERT INTO [dbo].[ItemTranx] VALUES (2,1,2,100,10,'01-JAN-2007','+100 @
>> $10')
>> -- How to find FIFO cost (expecting 11.33) for AmountPerUnit in this
>> line?:
>> INSERT INTO [dbo].[ItemTranx] VALUES (3,1,2,-75,11.33,'01-JAN-2007','-75
>> @
>> $11.33 ((50*12)+(25*10))/75')
>> INSERT INTO [dbo].[ItemTranx] VALUES (4,1,1,100,14,'01-JAN-2007','+100 @
>> $14')
>> INSERT INTO [dbo].[ItemTranx] VALUES (5,1,1,100,16,'01-JAN-2007','+100 @
>> $16')
>> -- How to find FIFO cost (expecting 11.60) for AmountPerUnit in this
>> line?:
>> INSERT INTO [dbo].[ItemTranx] VALUES
>> (6,1,3,-125,11.60,'01-JAN-2007','-125 @
>> $11.60 ((75*10)+(50*14))/125')
>> -- How to find FIFO cost (expecting 15.20) for AmountPerUnit in this
>> line?:
>> INSERT INTO [dbo].[ItemTranx] VALUES (7,1,3,-125,15.20,'01-JAN-2007',
>> '-125
>> @ $15.20 ((50*14)+(75*16))/125')
>>
>>
>>
>
>