SQL - 计算产品的累计平均成本价

SQL - Calculate cumulative average cost price for a product

我想知道是否有人至少可以为我指出这个问题的正确方向。

我需要计算库存的平均成本,但需要注意的是,它只能根据最新采购的产品计算,与我们的库存相关。

为了更好地解释产品 x,我们以不同的成本从不同的供应商处采购了总共 1,200 件。我们只剩下 150 件库存,因此,要获得剩余物品的平均购买价格和价值,我们需要从最近购买的 150 件中获得产品的平均成本 .

我有一个产生以下内容的视图:

 ProductId (int) - PK
 ProductName (varchar(150))
 StockInHand (int)

相关表格如下(t运行方便使用)

采购订单

PurchaseOrderId (int) - PK
PurchaseOrderDate (DateTime)
PurchaseOrderStatus (int) - FK

采购订单状态 - 1 = 打开,2 = 签入

采购订单行

PurchaseOrderLineId (int) - PK 
Qty (int)
UnitPrice (decimal(18,2))
ProductId (int) - FK
PurchaseOrderId (int) - FK

更新

我在这里创建了一个 sql-fiddle:

http://sqlfiddle.com/#!18/69288/1

你会看到我有3个商品采购订单:

1:数量 20 @ £40ea
2: 数量 20 @ £30ea
3: 数量 10 @ £25ea

我有两个相同商品的订单:

1:数量 10
2: 数量 15

据此,我可以得到手头的库存:25

我需要我所剩股票的平均买入价。

我还剩 25 个单位,所以我需要从最新的采购订单向后计算以获得价值。

我将从采购订单 3 中提取 10 个,从采购订单 2 中提取 15 个:

10 * 25 英镑 = 250 英镑
15 * 30 英镑 = 450 英镑

700 英镑 / 25 = 28 英镑

我希望这能让我的问题更清楚!

谢谢

更新 2

非常感谢 Sticky Bit 抽出时间 post 解决了我的问题,并如此周到地解释了它。

我已经在我的开发数据库上试过了,但似乎有问题。

同一产品我有 4 个采购订单(其中两个在同一天下达)

我还没有弄清楚如何在这个文本编辑器中优雅地格式化表格,所以请耐心等待:

PurchaseOrderId / PurchaseOrderDate
2 / 2018-07-28
3 / 2018-07-29
4 / 2018-07-30
5 / 2018-07-30

我有以下 PurchaseOrderLine

PurchaseOrderLineId / PurchaseOrderId / ProductId / Qty / 单价
3 / 2 / 8 / 20 / 400.00
4 / 3 / 8 / 40 / 420.00
5 / 4 / 8 / 25 / 500.00
6 / 5 / 8 / 1 / 200.00

运行 以下:

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;

给我这些结果:

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

您会注意到 7 月 30 日购买的产品的平均成本有所降低(它是两个价格之间的平均值,没有考虑数量 - 我不确定这是否是设计使然? )

如果我然后 运行 以下内容:

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;

我得到以下结果:

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

同样,关于单价,这里似乎有些不对劲。

非常感谢任何帮助!

亲切的问候

我没有看到 'UnitCost,',所以我将在我的代码示例中使用 'UnitPrice' 作为成本。

我不知道这是否完美,但它可能会帮助您找到正确的方向。

SELECT (SUM(UnitPrice)/150) FROM OrderDetails
WHERE PurchaseOrderId IS BETWEEN 1050 AND 1200
GO
  1. 首先我们需要找到一个查询来为我们提供每种产品的当前库存水平。为此,我们将 purchaseorderlineorderline 连接到 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;
    
  2. 接下来我们需要每个产品和天(purchaseorders)的库存数量。为此,我们内部加入 purchaseorderpurchaseorderline。我们再次汇总以说明可能的情况,即同一产品在同一天下了多个订单。

    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;
    

    我们现在可以使用之前的结果和window函数来得到每天的库存数量和产品平均价格的总和。

    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;
    

现在我们使用 OUTER APPLY 将 1. 和 2. 的结果放在一起。对于每种产品,我们 select TOP 1 结果来自 2. 按降序排列的日期 - 即首先是较年轻的订单 - 库存数量大于或等于当前库存数量。

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;