I was wondering if anyone could at least point me in the right direction with this issue.
I need to calculate the average cost of inventory but the caveat being that it should only be calculated on the latest procurement of products, relating to what we have in stock.
To try and explain in a better fashion, product x, we have purchased in total 1,200 units from various suppliers at different costs. We only have 150 units left in stock so, to get the average purchase price and value of the remaining items, we would need to get the average cost of the products from the latest 150 units purchased only .
I have a view which produces the following:
ProductId (int) - PK
ProductName (varchar(150))
StockInHand (int)
The related tables are as follows (truncated for ease of use)
PurchaseOrder
PurchaseOrderId (int) - PK
PurchaseOrderDate (DateTime)
PurchaseOrderStatus (int) - FK
Purchase order status - 1 = Open, 2 = Checked In
PurchaseOrderLine
PurchaseOrderLineId (int) - PK
Qty (int)
UnitPrice (decimal(18,2))
ProductId (int) - FK
PurchaseOrderId (int) - FK
UPDATE
I have created an sql-fiddle here:
http://sqlfiddle.com/#!18/69288/1
You will see that I have three purchase orders of goods:
1: Qty 20 @ £40ea
2: Qty 20 @ £30ea
3: Qty 10 @ £25ea
I have two orders of the same goods:
1: Qty 10
2: Qty 15
From this, I can get the stock on hand: 25
I need the average purchase price of the stock I have left.
I have 25 units left so I need to work backwards from the latest purchase orders to get the value.
I will take 10 from purchase order 3 and 15 from purchase order 2:
10 * £25 = £250
15 * £30 = £450
£700 / 25 = £28
I hope this makes my problem clearer!
Thank you
UPDATE 2
Thank you very much, Sticky Bit for taking the time out to post a solution to my problem and for explaining it so thoughtfully.
I have tried this on my dev DB and seem to have a problem.
I have 4 purchase orders for the same product (with two placed on the same day)
I have not worked out how to format tables gracefully in this text editor so please bear with me:
PurchaseOrderId / PurchaseOrderDate
2 / 2018-07-28
3 / 2018-07-29
4 / 2018-07-30
5 / 2018-07-30
I have the following PurchaseOrderLine
PurchaseOrderLineId / PurchaseOrderId / ProductId / Qty / UnitPrice
3 / 2 / 8 / 20 / 400.00
4 / 3 / 8 / 40 / 420.00
5 / 4 / 8 / 25 / 500.00
6 / 5 / 8 / 1 / 200.00
Running the following:
SELECT pol.productid,
po.purchaseorderdate,
sum(pol.qty) qty,
avg(pol.unitprice) unitprice
FROM purchaseorder po
INNER JOIN purchaseorderline pol
ON pol.purchaseorderid = po.purchaseorderid
GROUP BY pol.productid,
po.purchaseorderdate;
Gives me these results:
8 2018-07-28 00:00:00.000 20 400.000000
8 2018-07-29 00:00:00.000 40 420.000000
8 2018-07-30 00:00:00.000 26 350.000000
You will note that the average cost for the products purchased on 30th July is off (it is taking the average between the two prices and not taking the qty into account - I'm not sure if this is by design?)
If I then run the following:
SELECT po.productid,
po.purchaseorderdate,
sum(po.qty) OVER (PARTITION BY po.productid
ORDER BY po.purchaseorderdate) qty,
sum(po.unitprice) OVER (PARTITION BY po.productid
ORDER BY po.purchaseorderdate) unitprice
FROM (SELECT pol.productid,
po.purchaseorderdate,
sum(pol.qty) qty,
avg(pol.unitprice) unitprice
FROM purchaseorder po
INNER JOIN purchaseorderline pol
ON pol.purchaseorderid = po.purchaseorderid
GROUP BY pol.productid,
po.purchaseorderdate) po;
I get the following results:
8 2018-07-28 00:00:00.000 20 400.000000
8 2018-07-29 00:00:00.000 60 820.000000
8 2018-07-30 00:00:00.000 86 1170.000000
Again, something seems to be amiss here with regards to the unitprice.
Any help greatly appreciated!
Kind regards
I don't see 'UnitCost,' so I'm going to use 'UnitPrice' as the cost in my code example.
I don't know that this is perfect, but it may help you in the right direction.
SELECT (SUM(UnitPrice)/150) FROM OrderDetails
WHERE PurchaseOrderId IS BETWEEN 1050 AND 1200
GO
First we need to find a query to give us the current stock level for each product. For that, we left join purchaseorderline
and orderline
to product
and calculate the differences for each row. Since a product can be in multiple orders we additionally aggregate the result, to get the overall difference -- the current stock level -- for each product.
SELECT p.productid, p.productname, sum(coalesce(pol.qty, 0) - coalesce(ol.qty, 0)) qty FROM product p LEFT JOIN purchaseorderline pol ON pol.productid = p.productid LEFT JOIN orderline ol ON ol.productid = p.productid GROUP BY p.productid, p.productname;
Next we need the quantity, that was stocked for each product and day (of purchaseorders
). To get that, we inner join purchaseorder
and purchaseorderline
. Again we aggregate to account for the possible case, that multiple orders on the same day were made for the same product.
SELECT pol.productid, po.purchaseorderdate, sum(pol.qty) qty, sum(pol.qty * pol.unitprice) unitprice FROM purchaseorder po INNER JOIN purchaseorderline pol ON pol.purchaseorderid = po.purchaseorderid GROUP BY pol.productid, po.purchaseorderdate;
We can now use the previous result and window functions to get the sum of the quantity stocked and the average price of the products up to each day.
SELECT po.productid, po.purchaseorderdate, sum(po.qty) OVER (PARTITION BY po.productid ORDER BY po.purchaseorderdate) qty, sum(po.unitprice) OVER (PARTITION BY po.productid ORDER BY po.purchaseorderdate) / sum(po.qty) OVER (PARTITION BY po.productid ORDER BY po.purchaseorderdate) unitprice FROM (SELECT pol.productid, po.purchaseorderdate, sum(pol.qty) qty, sum(pol.qty * pol.unitprice) unitprice FROM purchaseorder po INNER JOIN purchaseorderline pol ON pol.purchaseorderid = po.purchaseorderid GROUP BY pol.productid, po.purchaseorderdate) po;
Now we put the results from 1. and 2. together using OUTER APPLY
. For each product, we select the TOP 1
result from 2. ordered by the day descending -- ie younger orders first --, that stocked a quantity greater than or equal to the one currently in stock.
SELECT p.productid,
p.productname,
po.unitprice
FROM (SELECT p.productid,
p.productname,
sum(coalesce(pol.qty, 0) - coalesce(ol.qty, 0)) qty
FROM product p
LEFT JOIN purchaseorderline pol
ON pol.productid = p.productid
LEFT JOIN orderline ol
ON ol.productid = p.productid
GROUP BY p.productid,
p.productname) p
OUTER APPLY (SELECT TOP 1
po.unitprice
FROM (SELECT po.productid,
po.purchaseorderdate,
sum(po.qty) OVER (PARTITION BY po.productid
ORDER BY po.purchaseorderdate) qty,
sum(po.unitprice) OVER (PARTITION BY po.productid
ORDER BY po.purchaseorderdate)
/
sum(po.qty) OVER (PARTITION BY po.productid
ORDER BY po.purchaseorderdate) unitprice
FROM (SELECT pol.productid,
po.purchaseorderdate,
sum(pol.qty) qty,
sum(pol.qty * pol.unitprice) unitprice
FROM purchaseorder po
INNER JOIN purchaseorderline pol
ON pol.purchaseorderid = po.purchaseorderid
GROUP BY pol.productid,
po.purchaseorderdate) po) po
WHERE po.productid = p.productid
AND po.qty >= p.qty
ORDER BY po.purchaseorderdate DESC) po;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.