How to implement FIFO in sql

前端 未结 4 945
星月不相逢
星月不相逢 2020-12-16 05:35

I working on FIFO implementation in sql. I have Batch number concept in my application. If suppose I am selling on inventory then my application should tell me that which in

相关标签:
4条回答
  • 2020-12-16 05:55

    One query .. like this

    This should be tweaked for you case as you have groups and other stuff, is only for example purposes.

    ;with qty as (
      select 15 as value
    )
    ,l as (
      select 
        ROW_NUMBER () over (order by accept_date desc) rn
        ,*
      from xxx
    )
    ,q as (
      select 
        batch_no
        ,accept_date
        ,case when value>qty then value-qty else 0 end as remainder
        ,case when value>qty then qty else value end as used
        ,rn
      from l
      cross join qty
      where rn=1
      union all
      select 
        r.batch_no
        ,r.accept_date
        ,case when q.remainder>r.qty then q.remainder-r.qty else 0 end  as remainder
        ,case when q.remainder>r.qty then r.qty else q.remainder end as used
        ,r.rn
      from q 
      join l r
      on q.rn+1 = r.rn
      where  q.remainder!=0
    )
    select * 
    from q
    where used != 0
    

    and the fiffle for it http://sqlfiddle.com/#!6/9b063/34/0

    0 讨论(0)
  • 2020-12-16 05:56

    Below should work for you

    Create table RS_GIN_Master
    (id int,
     qty int,
     batch_no varchar(5),
     accept_date Datetime
     )
    GO
    Insert into RS_GIN_Master (id, qty, batch_no, accept_date)
    values(1,10,'BT001','2018-04-06')
    Insert into RS_GIN_Master (id, qty, batch_no, accept_date)
    values(2,10,'BT002','2018-04-04')
    Insert into RS_GIN_Master (id, qty, batch_no, accept_date)
    values(3,15,'BT003','2018-05-06')
    GO
    ----------------------------
    CREATE PROC FIFO
     @TakenQty int
    AS
    BEGIN
     WITH cte AS (SELECT *, SUM(qty) OVER (ORDER BY accept_date, id ASC) as CumQty FROM RS_GIN_Master WHERE qty>0)
     SELECT TOP ((SELECT COUNT(*) FROM cte WHERE CumQty <@TakenQty)+1) batch_no, accept_date,
         CASE
              WHEN CumQty<@TakenQty THEN qty
                  ELSE @TakenQty -(CumQty-Qty)
          END AS TakenOut
     FROM cte
    END
    

    Result

    | batch_no |          accept_date | TakenOut |
    |----------|----------------------|----------|
    |    BT002 | 2018-04-04T00:00:00Z |       10 |
    |    BT001 | 2018-04-06T00:00:00Z |        5 |
    

    http://www.sqlfiddle.com/#!18/f7ee7/1

    0 讨论(0)
  • 2020-12-16 06:01

    You need to create a stored procedure in your database and taking the quantity from your stock table. And you should also have the id of each record to update that records from where u have taken that qty.

    Alter PROCEDURE sp_UpdateStockForSale
        @batchNO varchar(10), 
        @qty decimal(9,3)
    AS
    BEGIN
        Create Table #tmpOutput(ID int identity(1,1), StockID int, batchNo varchar(10), qty decimal(9,3));
        SET NOCOUNT ON;
    
        DECLARE @ID int;
        DECLARE @Stock Decimal(9,3);
    
        DECLARE @TEMPID int;
        Select @TEMPID=(Max(ID)+1) From RS_GIN_Master Where qty > 0 And batch_no = @batchNO;
    
        While (@qty > 0) BEGIN
            Select @ID=ID, @Stock=qty From RS_GIN_Master Where qty > 0 And batch_no = @batchNO AND ID < @TEMPID Order By accept_date Desc;
    
            --If Outward Qty is more than Stock
            IF (@Stock < @qty) BEGIN
                SET @qty = @qty - @Stock;
                SET @Stock = 0;
            END
            --If Outward Qty is less than Stock
            ELSE BEGIN          
                SET @Stock = @Stock - @qty;
                SET @qty = 0;
            END    
            Insert Into #tmpOutput(StockID,batchNo,qty)Values(@ID,@batchNO,@Stock);
            SET @TEMPID = @ID;
            --This will update that record don't need it now.
            --Update RS_GIN_Master Set qty = @Stock Where ID=@ID
        END
        Select StockID, batchNo, qty From #tmpOutput;
    END
    GO
    

    The above example is not compiled but, you can get the logic how you can retrieve the records from your stock table according to FIFO method. You can use accept_date instead of ID in RS_GIN_Master table. but, i would prefer to make it unique so, if i want to get a specific record then it can be possible.

    0 讨论(0)
  • 2020-12-16 06:16

    This should work for you:
    Working sample on Fiddle

    CREATE FUNCTION [dbo].[GetBatchAmounts]
    (
        @requestedAmount int
    
    )
    RETURNS 
    @tBatchResults TABLE 
    (   
        Batch nvarchar(50),
        Amount int
    )
    AS
    BEGIN
        /*This is just a mock of ersults of your query*/
        DECLARE @RS_GIN_Master TABLE( 
    
         Qty int,
         batch_no NVARCHAR(max),
         accept_date DATETIME
        )
    
        insert into @RS_GIN_Master(Qty,batch_no,accept_date)
        SELECT 10,'BT002', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(4 AS varchar) AS DATETIME)
    
        insert into @RS_GIN_Master(Qty,batch_no,accept_date)
        SELECT 10,'BT003', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(5 AS varchar) AS DATETIME)
    
        insert into @RS_GIN_Master(Qty,batch_no,accept_date)
        SELECT 10,'BT001', CAST(CAST(2014 AS varchar) + '-' + CAST(8 AS varchar) + '-' + CAST(6 AS varchar) AS DATETIME)
        /*---------------------------*/
    
         DECLARE @Qty int
         DECLARE @batch_no NVARCHAR(max)
         DECLARE @accept_date DATETIME
    
    
        DECLARE myCursor CURSOR FOR
    
        SELECT Qty, batch_no, accept_date FROM @RS_GIN_Master ORDER BY accept_date ASC
    
        OPEN myCursor
    
        FETCH NEXT FROM myCursor INTO  @Qty, @batch_no,@accept_date
    
        WHILE (@@FETCH_STATUS = 0 AND @requestedAmount > 0 ) 
        BEGIN
    
            Declare @actualQty int
            IF @requestedAmount > @Qty
                SET @actualQty = @Qty
            ELSE    
                SET @actualQty = @requestedAmount
    
    
            INSERT INTO @tBatchResults (batch, Amount)
            SELECT @batch_no, @actualQty
    
            set @requestedAmount  = @requestedAmount - @actualQty
    
            FETCH NEXT FROM myCursor INTO @Qty, @batch_no,@accept_date
    
        END /*WHILE*/
    
        CLOSE myCursor
        DEALLOCATE myCursor
    
        RETURN
    END
    

    Just make sure to replace the marked part of the function with your query...

    0 讨论(0)
提交回复
热议问题