sql >> Databasteknik >  >> RDS >> Sqlserver

FIFO-baserad lagervärdering i SQL Server

Förvånansvärt svårt att få rätt. Jag misstänker att det skulle vara lättare att använda SQL Server 2012 som stöder löpande summor i fönsterfunktioner. Hur som helst:

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

Den första observationen är att vi inte behöver göra något speciellt för OUT transaktioner - vi behöver bara veta den totala kvantiteten. Det är vad TotalOut CTE beräknar. De två första CTE:erna fungerar med IN transaktioner och beräkna vilket "intervall" av lager var och en representerar - ändra den slutliga frågan till att bara select * from RunningTotals för att få en känsla för det.

Den sista SELECT uttalandet hittar rader som inte har uttömts helt av utgående transaktioner och bestämmer sedan om det är hela kvantiteten av den inkommande transaktionen, eller om det är transaktionen som går över den utgående summan.



  1. Finns det en motsvarighet till SQL Servers SET NOCOUNT i MySQL?

  2. MySQL:Kopiera tabell till en annan tabell med en extra kolumn

  3. Fel- ORA-22835:Bufferten är för liten för konvertering från CLOB till CHAR eller BLOB till RAW

  4. Skapa trigger för före infogning