【问题标题】:FIFO based stock inventory valuation in SQL Server [closed]SQL Server中基于FIFO的库存估价[关闭]
【发布时间】:2012-04-26 15:02:33
【问题描述】:

我有一个这样的股票交易表:

Item   Date         TxnType Qty  Price
ABC   01-April-2012   IN    200 750.00
ABC   05-April-2012   OUT   100     
ABC   10-April-2012   IN     50 700.00
ABC   16-April-2012   IN     75 800.00
ABC   25-April-2012   OUT   175     
XYZ   02-April-2012   IN    150 350.00
XYZ   08-April-2012   OUT   120     
XYZ   12-April-2012   OUT    10     
XYZ   24-April-2012   IN     90 340.00

我需要 FIFO(先进先出)中每件商品的库存价值,这意味着应该先消费第一个购买的商品。 以上数据的产出存量估值为:

Item  Qty      Value
ABC   50    40000.00
XYZ   110   37600.00

请帮我解决。

【问题讨论】:

  • 你能解释一下你输出的数字应该相加吗?

标签: tsql sql-server-2005


【解决方案1】:

出乎意料地难以做到正确。我怀疑使用支持在窗口函数中运行总和的 SQL Server 2012 会更容易。总之:

declare @Stock table (Item char(3) not null,[Date] datetime not null,TxnType varchar(3) not null,Qty int not null,Price decimal(10,2) null)
insert into @Stock(Item ,  [Date] ,        TxnType, Qty,  Price) values
('ABC','20120401','IN',    200, 750.00),
('ABC','20120405','OUT',   100 ,null  ),
('ABC','20120410','IN',     50, 700.00),
('ABC','20120416','IN',     75, 800.00),
('ABC','20120425','OUT',   175, null  ),
('XYZ','20120402','IN',    150, 350.00),
('XYZ','20120408','OUT',   120 ,null  ),
('XYZ','20120412','OUT',    10 ,null  ),
('XYZ','20120424','IN',     90, 340.00);

;WITH OrderedIn as (
    select *,ROW_NUMBER() OVER (PARTITION BY Item ORDER BY [DATE]) as rn
    from @Stock
    where TxnType = 'IN'
), RunningTotals as (
    select Item,Qty,Price,Qty as Total,0 as PrevTotal,rn from OrderedIn where rn = 1
    union all
    select rt.Item,oi.Qty,oi.Price,rt.Total + oi.Qty,rt.Total,oi.rn
    from
        RunningTotals rt
            inner join
        OrderedIn oi
            on
                rt.Item = oi.Item and
                rt.rn = oi.rn - 1
), TotalOut as (
    select Item,SUM(Qty) as Qty from @Stock where TxnType='OUT' group by Item
)
select
    rt.Item,SUM(CASE WHEN PrevTotal > out.Qty THEN rt.Qty ELSE rt.Total - out.Qty END * Price)
from
    RunningTotals rt
        inner join
    TotalOut out
        on
            rt.Item = out.Item
where
    rt.Total > out.Qty
group by rt.Item

第一个观察是我们不需要为OUT 交易做任何特别的事情——我们只需要知道总量。这就是TotalOut CTE 计算的结果。前两个 CTE 使用 IN 交易,并计算每个股票的“间隔”代表什么 - 将最终查询更改为仅 select * from RunningTotals 以感受一下。

最后的SELECT 语句查找尚未被传出事务完全耗尽的行,然后决定是该传入事务的全部数量,还是跨越传出总数的事务。

【讨论】:

  • 亲爱的@Damien_The_Unbeliever,感谢您提供的出色解决方案。我正在使用游标来执行此操作,这需要花费大量时间。您能否建议如何使用 LIFO 模型做同样的事情?非常感谢您的帮助。
  • @Nagesh - 会明显更复杂 - 没有任何事情发生在我的脑海中 - 因为in 20,价格为 A,out 10,in 20,价格为 B , out 10 可能会留下 20 个,由价格为 A 的 10 个和价格为 B 的 10 个组成。你不能做出我在上面所做的简化假设,即所有 outs 都是平等的。
  • 亲爱的@Damien_The_Unbeliever 又一期。如果 IN 和 OUT 事务都存在,您提供的 SQL 将显示库存值。如果我只有 IN 它不会显示这些项目的结果。请修改。
  • @Nagesh - 将底部的inner join 更改为left join,并将对out.Qty 的每个引用更改为COALESCE(out.Qty,0),它应该可以工作。
【解决方案2】:

我认为您必须为此使用详细事务表。 像 Stock、StockDetail、StockDetailTransaction。 在此 StockDetailTransaction 表中包含 Stock 的 FIFO 条目。 当 Item In/Out 时在 StockDetailTransaction 中添加记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 2018-06-14
    相关资源
    最近更新 更多