Đáng ngạc nhiên là khó khăn để nhận được đúng. Tôi nghi ngờ sẽ dễ dàng hơn bằng cách sử dụng SQL Server 2012 hỗ trợ chạy tính tổng trong các chức năng cửa sổ. Nhưng dù sao:
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
Quan sát đầu tiên là chúng ta không cần làm bất cứ điều gì đặc biệt cho OUT
giao dịch - chúng tôi chỉ cần biết tổng số lượng. Đó là những gì TotalOut
CTE tính toán. Hai CTE đầu tiên hoạt động với IN
giao dịch và tính toán "khoảng thời gian" của mỗi cổ phiếu đại diện - thay đổi truy vấn cuối cùng thành chỉ select * from RunningTotals
để cảm nhận điều đó.
SELECT
cuối cùng câu lệnh tìm các hàng chưa được sử dụng hết bởi các giao dịch gửi đi và sau đó quyết định xem đó là toàn bộ số lượng của giao dịch đến đó hay đó là giao dịch nằm trong tổng số gửi đi.