<intro>
I'm modeling the use/consumption of ingredients in a bakery... Each recipe requires a set of (ingredient, Weight) to yield a number of loaves. I have a table of Purchases (PurchaseID, VendorID, PurchaseDate, IngredientID, UnitPrice, UnitsPurchased). When I "use/allocate" ingredients from inventory to a batch (BatchID, RecipeID, BatchCount, Date), I want to basically do a First in First Out (FIFO), so one "allocation" may span two (or more) purchases of ingredient at different prices.
There are purchases of Product at one or more price points. I can use up one "bin" (all the weight at one price point), and then move on to the next "bin". Can I do that without using a cursor? I know I can do FIFO kind of by using TOP(n), but it's hard because what happens when the "top" say 60# that I may need for a batch can come from two different "bins". Can I do that without a cursor? If I used a cursor, I'd get a "set" of ingredients where there are some in stock, maybe at two different price points. I could then take all of whats left in the first "bin" and then take the rest of what I need from the next newest "bin"
CREATE TABLE Purchases (
IngredientID INT NOT NULL
,PurchaseDate DATE NOT NULL
,UnitPrice SMALLMONEY
,UnitsPurchased INT
-- ,UnitWeight DECIMAL()
);
-- all of the unit prices are
INSERT INTO Purchases (IngredientID, PurchaseDate, UnitPrice, UnitsPurchased, UnitWeight)
VALUES (1, '01-Jan-2022', 48.00, 6, 50),
(1, '08-Jan-2022', 48.00, 12, 50),
(1, '15-Jan-2022', 49.00, 12, 50),
(1, '31-Jan-2022', 50.00, 6, 50);
LOTS: (1, 48.00, 18, 50), (1, 49.00, 12, 50), (1, 50.00, 6, 50)
so the "lots" (single ingredient at one unit price)
SELECT IngredientID
,UnitPrice
,TotalUnits = SUM(UnitsPurchased)
,TotalCost = SUM(UnitsPurchased * UnitPrice)
FROM Purchases
GROUP BY IngredientID, UnitPrice;
Then I'd sort the bins by PurchaseDate, and then take out of the "top"/first bin until the bin is empty and go to the next.
So if I needed 350# of ingredientID = 1, I'd need the full Jan 1 lot and then 50# from the second. Can I do that without a cursor?
I know I can create a running total using (say) a CTE, but can I then use that to determine what the total cost of a batch of bread? The part I don't understand how to do is to determine which lot (and at what unit price) I allot that to a batch.
Can I do this without a cursor? If so, how? I could use the cursor to allocate the different lots of ingredient to a batch and decrease the stock part too.
CREATE TABLE PurchaseFact (
PurchaseID INT IDENTITY(1,1)
,IngredientID INT NOT NULL
,UnitPrice SMALLMONEY NOT NULL
,UnitsPurchased INT
,PurchaseDate DATETIME NOT NULL
,VendorID INT NOT NULL
)
Here's the Recipe table
CREATE TABLE [dbo].[RecipeIngredient](
[RecipeID] [int] NOT NULL,
[IngredientID] [int] NOT NULL,
[RecipeIngredientWeight] [int] NOT NULL
) ON [PRIMARY];
One thought I had was to keep track of the weight allocated out of each "lot" (Purchase of an ingredient). I can calculate the total weight really easily - it's just Purchase.Units * Ingredient.UnitWeight)
So how would I do the allocations? Would I basically have to use a cursor to get from the first Purchase Order with any weight that's not been allocated and go that way? (Kind of like using a recordset in Access and looping over purchase orders, "allocating" whatever's left of the PO weight for that ingredient, and going to the next if there isn't enough weight left from that purchase order, and then go on to the next one? (and logging the (PONumber, IngredientID, Weight, BatchID) so I know what the weight was allocated to.)
Does it even make sense to do something "Get me all the "requests" for ingredients in this batch where PO.WeightRemaining is sufficient to serve the Allocation.WeightRequired request and do the whole thing as a cursor/recordset where I loop over the Allocations in the cursor/recordset and go to the next Purchase Order if there isn't enough in the first one to meet the required weight?
The goal is to get the actual cost of the Ingredients for a given recipe. (and some ingredient prices are volatile, so just taking the most recent price is going to cause problems). Can I do this without a cursor? A normal batch of product will never use an entire package of anything (It's bread, and flour comes in 50 pound bags, and since he only makes like 400 loaves a week total, no bake order (ProductID, Date, BatchCount) will use a huge amount of any single ingredient.
If It's not clear what I'm talking about, go ahead and ask questions.
Thanks!
Pieter