如何在sql中实现FIFO

时间:2014-08-06 05:42:54

标签: sql sql-server

我在sql中进行FIFO实现。 我的应用程序中有批号概念。 如果假设我在库存中销售,那么我的应用程序应该告诉我哪个库存是先到的。 让我们。假设我在8月4日,8月5日和8月购买了库存'A'。第六 - 8

On 4th Aug - A Inventory has batch number   BT002 - 10 (Qty)
On 5th Aug - A's Inventory has batch number BT003 - 15 (Qty)
On 6th Aug - A's Inventory has batch number BT001 - 10 (Qty)

所以,现在我有了股票现在在我的手中如下:

A Inventory
BT002 - 10 - 4-Aug
BT003 - 15 - 5-Aug
BT001 - 10 - 6-Aug

现在,如果我想将该库存出售给任何人,那么我的应用程序应该告诉我应该卖掉 BT002(批号)库存首先是因为它首先出现。

这就是我在申请中使用的概念。

现在我想从'A'(库存)出售15个数量。

然后O / p应该是这样的:

BT002 - 10
BT003 - 5

这是我的查询:

SELECT ISNULL(SUM(qty),0) AS Qty,batch_no,accept_date  FROM RS_GIN_Master 
GROUP BY batch_no,accept_date
HAVING ISNULL(SUM(qty),0) <= 15
ORDER BY accept_date asc

给定查询的O / p:

enter image description here

我怎样才能获得这样的O / P:

BT002 - 10
BT003 - 5

任何帮助将不胜感激。 先感谢您。

4 个答案:

答案 0 :(得分:3)

您需要在数据库中创建存储过程并从库存表中获取数量。而且你还应该拥有每条记录的id来更新你从那里获取该数量的记录。

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

上面的示例没有编译,但是,您可以获得逻辑如何根据FIFO方法从库存表中检索记录。您可以在RS_GIN_Master表中使用accept_date代替ID。但是,我更愿意让它变得独一无二,所以,如果我想得到一个特定的记录,那么它就有可能。

答案 1 :(得分:3)

这对你有用:
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

只需确保用查询替换函数的标记部分......

答案 2 :(得分:2)

一个查询..像这样

这应该为您调整,因为您有组和其他东西,仅用于示例目的。

;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

和它的fiffle http://sqlfiddle.com/#!6/9b063/34/0

答案 3 :(得分:0)

下面应该为您工作

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

结果

| 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