sql >> Database >  >> RDS >> Sqlserver

Op FIFO gebaseerde voorraadwaardering in SQL Server

Verrassend moeilijk om goed te krijgen. Ik vermoed dat het gemakkelijker zou zijn om SQL Server 2012 te gebruiken, die het uitvoeren van sommen in vensterfuncties ondersteunt. Hoe dan ook:

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

De eerste observatie is dat we niets speciaals hoeven te doen voor OUT transacties - we moeten alleen de totale hoeveelheid weten. Dat is wat de TotalOut CTE berekent. De eerste twee CTE's werken met IN transacties, en bereken welk "interval" van de voorraad elk vertegenwoordigt - verander de laatste zoekopdracht in select * from RunningTotals om daar een gevoel voor te krijgen.

De laatste SELECT statement vindt rijen die niet volledig zijn uitgeput door uitgaande transacties en beslist vervolgens of het de hele hoeveelheid van die inkomende transactie is, of dat dat de transactie is die het uitgaande totaal overschrijdt.



  1. De beste manier om XML-gegevens te versnipperen in SQL Server-databasekolommen

  2. Postgres, update en vergrendel bestellen

  3. Hoe kan ik CONCAT tijdens SELECT in MySQL als kolomnaam gebruiken?

  4. MySQL:Kan een opgeslagen procedure een Java-programma aanroepen?