重建公司kardex

Rebuild company kardex

我正在尝试重建我的公司 kardex。我需要使用 "Average Cost Method",它应该考虑每笔交易在其特定日期时间的平均成本。

我有一个简单的 table,其中包含所有 incoming/outgoing 库存交易(所有移动)。

每笔传入的交易(购买)都正确定价,因为我从其相应的发票中提取了单位成本。

问题: 所有销售交易(流出库存)都没有单位成本(因为我需要重建这些成本)。 我知道我可以使用游标,但我们都知道那里的性能问题。

我准备了一个简单的数据来更好的说明我自己。 请注意所有销售(传出交易)都没有成本,我认为使用简单的窗口函数不会有帮助,因为每一行都取决于之前的计算。所以,我有点需要基于之前计算的计算..??

DECLARE @Resultado TABLE (Row_ID BIGINT IDENTITY NOT NULL PRIMARY KEY, Inventory_Name VARCHAR(100), Transaction_Date DATETIME, DIRECTION BIT, Transaction_Name VARCHAR(100),Transaction_Quantity INT, Transaction_UnitCost NUMERIC(18,2), Transaction_Amount NUMERIC(18,2), AVERAGE_UNITCOST_AT_TRANSACTION_DATE NUMERIC(18,2))

INSERT INTO @Resultado ( Inventory_Name , Transaction_Date , DIRECTION , Transaction_Name , Transaction_Quantity , Transaction_UnitCost, Transaction_Amount, AVERAGE_UNITCOST_AT_TRANSACTION_DATE)
SELECT 'COMPUTER', '2017-01-01', 1, 'INCOMING PRODUCT; PRUCHASE', 100, 10, 100 * 10, 10
UNION ALL SELECT 'COMPUTER', '2017-01-02', 1, 'INCOMING PRODUCT; PURCHASE', 105, 11, 105 * 11, 10.51
UNION ALL SELECT 'COMPUTER', '2017-01-03', 1, 'INCOMING PRODUCT; PURCHASE', 110, 12, 110 * 12, 11.03
UNION ALL SELECT 'COMPUTER', '2017-01-04', 0, 'OUTGOING PRODUCT; SALES', -200, NULL, NULL, NULL
UNION ALL SELECT 'COMPUTER', '2017-01-05', 0, 'OUTGOING PRODUCT; SALES', -50, NULL, NULL, NULL
UNION ALL SELECT 'COMPUTER', '2017-01-06', 1, 'INCOMING PRODUCT; PURCHASE', 110, 10, 110 * 10, NULL
UNION ALL SELECT 'COMPUTER', '2017-01-07', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL
UNION ALL SELECT 'COMPUTER', '2017-01-08', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL
UNION ALL SELECT 'COMPUTER', '2017-01-09', 0, 'OUTGOING PRODUCT; SALES', -20, NULL, NULL, NULL

SELECT * FROM @Resultado

提示:如果您在问题中包含预期结果,将会很有帮助。

这个通用 Table 表达式 (CTE) 应该可以帮助您入门:

with CTE as (
  select Row_Id, Inventory_Name, Transaction_Date, Direction, Transaction_Name,
    Transaction_Quantity, Transaction_UnitCost,
    Transaction_Quantity as QuantityOnHand,
    Transaction_UnitCost as AverageUnitCost
    from @Resultado
    where Direction = 1 and Row_Id = 1 -- Starting condition for your single product sample data.
  union all
  select R.Row_ID, R.Inventory_Name, R.Transaction_Date, R.Direction, R.Transaction_Name,
    R.Transaction_Quantity, R.Transaction_UnitCost,
    -- The   TransactionQuantity   is already signed, so there is no need to multiple it by   ( Direction * 2 - 1 ) .
    CTE.QuantityOnHand + R.Transaction_Quantity,
    -- My accounting is pretty rusty, but this should do some sort of useful averaging.
    Cast( case
      when R.Direction = 0 then CTE.AverageUnitCost -- Sales don't affect the average unit cost.
      else ( CTE.AverageUnitCost * CTE.QuantityOnHand + R.Transaction_UnitCost * R.Transaction_Quantity ) /
        ( CTE.QuantityOnHand + R.Transaction_Quantity ) end
      as Numeric(18,2) )
    from CTE inner join
      @Resultado as R on R.Row_Id = CTE.Row_Id + 1 -- Row by row.
    )
  select Row_Id, Inventory_Name, Transaction_Date, Direction, Transaction_Name, Transaction_Quantity, Transaction_UnitCost,
    QuantityOnHand, AverageUnitCost
    from CTE;

select 语句末尾添加分号后,您可以 运行 它针对您的样本数据。

性能可能很差,因为您需要从第一行开始计算。添加列以维护 QuantityOnHandAveragreUnitCost 将允许您在发生新交易时更新数据,例如在触发器中。 (注意,更新和删除可能需要从时间开始重新计算。)

更现代的解决方案将使用 Lead/Lag,但我恰好回到 SQL Server 2008 R2。