Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Wycena zapasów magazynowych w oparciu o FIFO w SQL Server

Zaskakująco trudno to zrobić. Podejrzewam, że łatwiej byłoby użyć SQL Server 2012, który obsługuje uruchamianie sum w funkcjach okienkowych. W każdym razie:

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

Pierwsza obserwacja jest taka, że ​​nie musimy robić nic specjalnego dla OUT transakcje - wystarczy znać całkowitą ilość. To właśnie TotalOut CTE oblicza. Pierwsze dwa CTE działają z IN transakcji i oblicz, jaki „interwał” reprezentuje każdy z nich — zmień końcowe zapytanie, aby po prostu select * from RunningTotals aby to wyczuć.

Ostatni SELECT instrukcja znajduje wiersze, które nie zostały całkowicie wyczerpane przez transakcje wychodzące, a następnie decyduje, czy jest to cała ilość tej transakcji przychodzącej, czy też jest to transakcja, która obejmuje sumę wychodzącą.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak odjąć 30 dni od bieżącej daty za pomocą SQL Server

  2. Jaki jest cel braku słowa kluczowego w SQL Server 2012?

  3. serwer sql zautomatyzowane codzienne partycjonowanie tabel

  4. Nieoczekiwane zachowanie @@rowcount wewnątrz UDF w MS SQL 2019

  5. CTE w klauzuli From zapytania SQL