Overraskende svært at få ret. Jeg formoder, at det ville være nemmere at bruge SQL Server 2012, som understøtter kørende summer i vinduesfunktioner. Under alle omstændigheder:
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ørste observation er, at vi ikke behøver at gøre noget særligt for OUT
transaktioner - vi skal bare kende den samlede mængde. Det er hvad TotalOut
CTE beregner. De første to CTE'er fungerer med IN
transaktioner, og udregn, hvilket "interval" af lager hver repræsenterer - skift den endelige forespørgsel til bare at select * from RunningTotals
for at få en fornemmelse af det.
Den endelige SELECT
statement finder rækker, som ikke er blevet fuldstændig opbrugt af udgående transaktioner, og beslutter derefter, om det er hele mængden af den indgående transaktion, eller om det er den transaktion, der dækker den udgående total.