Anehnya sulit untuk mendapatkan yang benar. Saya menduga akan lebih mudah menggunakan SQL Server 2012 yang mendukung jumlah yang berjalan dalam fungsi windowing. Bagaimanapun:
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
Pengamatan pertama adalah kita tidak perlu melakukan sesuatu yang khusus untuk OUT
transaksi - kita hanya perlu mengetahui jumlah totalnya. Itulah TotalOut
CTE menghitung. Dua CTE pertama bekerja dengan IN
transaksi, dan hitung "interval" stok yang diwakili masing-masing - ubah kueri akhir menjadi select * from RunningTotals
untuk merasakannya.
SELECT
terakhir pernyataan menemukan baris yang belum sepenuhnya habis oleh transaksi keluar, dan kemudian memutuskan apakah itu seluruh jumlah transaksi masuk itu, atau apakah itu transaksi yang melampaui total keluar.