Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Оценка на запасите на база FIFO в SQL Server

Изненадващо трудно да се направи правилно. Подозирам, че би било по-лесно с помощта на SQL Server 2012, който поддържа текущи суми в прозоречни функции. Както и да е:

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

Първото наблюдение е, че не е нужно да правим нищо специално за OUT транзакции - просто трябва да знаем общото количество. Това е, което TotalOut CTE изчислява. Първите два CTE работят с IN транзакции и изчислете какъв „интервал“ на складовите наличности представлява всеки - променете крайната заявка просто на select * from RunningTotals за да усетите това.

Последният SELECT оператор намира редове, които не са били напълно изчерпани от изходящите транзакции, и след това решава дали това е цялото количество на тази входяща транзакция, или това е транзакцията, която обхваща изходящата обща сума.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server ИЗБЕРЕТЕ ПОСЛЕДНИ N реда

  2. Връщане на varchar(max) Изходен параметър от съхранена процедура, съкращаване до 4000 знака

  3. Пейджинг с Entity Framework 7 и SQL Server 2008

  4. SQL заявка - Променете формата на датата в заявката на ДД/ММ/ГГГГ

  5. Вземете резултат от динамичен SQL в съхранена процедура