【问题标题】:FIFO on inventory stocks库存库存先进先出
【发布时间】:2016-08-03 14:02:35
【问题描述】:

我有一个查询,它返回数据库中所有可用的股票。我 需要做一个存储过程来获取用户输入的具体商品的itemCode、batchNo、数量、价格。

----------------------------------------------
| id | itemCode | batchNo | availQty | price |
----------------------------------------------
| 1  | item_1   | 07292016|   5      |  5.50 |
| 2  | item_1   | 07312016|   10     |  5.50 |
| 3  | item_1   | 08012016|   2      |  6.00 |

我的问题是,如果用户输入了 6 个要购买的数量,我怎样才能得到结果的前 2 行以获得 6 个的总数量?

结果必须是:

07292016  --- 5
07312016  --- 1

【问题讨论】:

  • 发布您的查询以获得更多说明
  • 用你的 sql server 版本标记问题。如果它支持 SUM OVER() 解决方案很简单。
  • @jarlh,感谢您的澄清。
  • @KarthickRajan,先生,查询太长了,但我们假设表的输出或表中的值就像我发布的一样,
  • @serg, sql server 2008

标签: sql sql-server sql-server-2008


【解决方案1】:

我怀疑这是否有效并且查询是可怕的,但以下内容将为您提供您想要的:

-- Create Test Data
create table #Items
(
    id int not null primary key,
    itemCode varchar(30) not null,
    batchNumber varchar(30) not null,
    availQty int not null,
    price smallmoney not null
);

insert into #Items
values
    (1, 'item_1', '07292016', 5, 5.50),
    (2, 'item_1', '07312016', 10, 5.50),
    (3, 'item_1', '08012016', 2, 6.00)

select 
    *
from
    #Items
;

-- Set up required parameters
declare 
    @requiredItemCode varchar(30) = 'item_1',
    @requiredQty int = 6

-- The query to get the required result
select
    i.*,
    case
        when
            @requiredQty - 
            isnull(
                (
                    select
                        sum(availQty)
                    from
                        #Items i2
                    where
                        i2.itemCode = i.itemCode
                        and i2.id < i.Id
                ),
                0) < i.availQty
        then
            @requiredQty - 
            isnull(
                (
                    select
                        sum(availQty)
                    from
                        #Items i2
                    where
                        i2.itemCode = i.itemCode
                        and i2.id < i.Id
                ),
                0)
        else
            i.availQty
    end as qtyToTake
from 
    #Items i
where   
    i.ItemCode = @requiredItemCode
    and 
    case
        when
            @requiredQty - 
            isnull(
                (
                    select
                        sum(availQty)
                    from
                        #Items i2
                    where
                        i2.itemCode = i.itemCode
                        and i2.id < i.Id
                ),
                0) < i.availQty
        then
            @requiredQty - 
            isnull(
                (
                    select
                        sum(availQty)
                    from
                        #Items i2
                    where
                        i2.itemCode = i.itemCode
                        and i2.id < i.Id
                ),
                0)
        else
            i.availQty
    end > 0

-- Clean up test data
drop table #Items

输出:

id          itemCode batchNumber availQty    price
----------- -------- ----------- ----------- ---------------------
1           item_1   07292016    5           5.50
2           item_1   07312016    10          5.50
3           item_1   08012016    2           6.00

(3 row(s) affected)

id          itemCode batchNumber availQty    price                 qtyToTake
----------- -------- ----------- ----------- --------------------- -----------
1           item_1   07292016    5           5.50                  5
2           item_1   07312016    10          5.50                  1

(2 row(s) affected)

【讨论】:

  • 先生,您能告诉我有关“和 i2.id
  • “and i2.id i.Id,您将获得 id 为 2 和 3 的行,而不是第 1 和 2 行。
  • 还有其他方法可以在不使用 id 的情况下实现输出吗?因为我在想,id 的值可能不是按 asc 排序的。
  • 您可以替换排序数据的任何列的 ID。批号可能有效,但如果没有有关您在做什么的更多信息,就很难知道。
【解决方案2】:

试试这个

DECLARE @Tbl TABLE (id INT, itemCode NVARCHAR(50), batchNo NVARCHAR(50), availQty INT, price DECIMAL(5,2))

INSERT INTO @Tbl VALUES        
(1, 'item_1'   , '07292016',   5      ,  5.50 ),
( 2  , 'item_1',    '07312016'   ,10,  5.50),
( 3  , 'item_1',    '08012016'   ,2 ,  6.00 )


DECLARE @Quantity INT = 6

SELECT * 
FROM
    @Tbl
WHERE
    id <= (
            SELECT TOP 1
                  A.id
            FROM
            (
                SELECT
                    id ,
                    itemCode ,
                    batchNo ,
                    availQty ,
                    price,
                    (SELECT SUM(availQty) FROM @Tbl IT WHERE IT.id <= T.id)  AS TotalAmount
                FROM
                    @Tbl T
            ) A
            WHERE
                A.TotalAmount >= @Quantity
            ORDER BY A.id
          )

输出:

id  itemCode    batchNo     availQty    price
1   item_1      07292016    5           5.50
2   item_1      07312016    10          5.50

更新

SELECT
    R.id ,
    R.itemCode ,
    R.batchNo ,
    R.availQty ,
    R.price ,
    CASE WHEN R.MaxId = id THEN R.availQty - (TotalQuantity - @Quantity)
        ELSE R.availQty END OutQuantity
FROM
(
    SELECT 
        id ,
        itemCode ,
        batchNo ,
        availQty ,
        price,
        MAX(id) OVER (ORDER BY (SELECT NULL)) MaxId,
        SUM(availQty) OVER (ORDER BY (SELECT NULL)) TotalQuantity
    FROM
        @Tbl
    WHERE
        id <= (
                SELECT TOP 1
                      A.id
                FROM
                (
                    SELECT
                        id ,
                        itemCode ,
                        batchNo ,
                        availQty ,
                        price,
                        (SELECT SUM(availQty) FROM @Tbl IT WHERE IT.id <= T.id)  AS TotalAmount
                    FROM
                        @Tbl T
                ) A
                WHERE
                    A.TotalAmount >= @Quantity
                ORDER BY A.id
              )
) R
WHERE 
  @Quantity > 0

输出

id  itemCode    batchNo     availQty    price   OutQuantity
1   item_1      07292016    5           5.50    5
2   item_1      07312016    10          5.50    1

【讨论】:

  • 感谢您的帮助。但是你能告诉我如何在第 2 行中只获得 1 个数量吗?谢谢
  • 供参考,SUM(...) OVER (ORDER BY ...) 在早于 2012 年的 SQL Server 版本中不受支持。
【解决方案3】:

我还没有测试过,但是如果您有任何问题,您仍然可以在此基础上进行更改。希望你想要这个

  CREATE OR ALTER PROCEDURE dbo.getStock @item_Code nvarchar(30), @quantity  int
    AS 
    //Declare variables
    DECLARE @id INT
    DECLARE @itemCode nvarchar(30)
    DECLARE @batchNo nvarchar(30)
    DECLARE @qty INT
    DECLARE @cumulativeQty INT
    DECLARE @price DECIMAL(18,2)

    //Declare cursor
    DECLARE @getStock CURSOR
    SET @getStock = CURSOR FOR
    SELECT Id, ItemCode, batchNo, availQty, price
    FROM your_table
    WHERE ItemCode = @item_Code
    ORDER BY  batchNo ASC

    //Create temp table to store all of the intermediate stock records into it

    //If always make sure if its already exist just drop and recreate



IF OBJECT_ID('tempdb..#TmpStock') IS NOT NULL 
    BEGIN
        DROP TABLE #TmpStock
    END
    ELSE
    BEGIN
        CREATE TABLE #TmpStock(Id INT, ItemCode nvarchar(30), BatchNo nvarchar(30), Quatnity INT, Price Decimal(18,2))
    END


    //Open the cursor
    OPEN @getStudents 

    //Read the next row record into the cursor
    FETCH NEXT 
    FROM @getStock INTO @id, @itmCode, @batchNo, @qty, @price


    SET @cumulativeQty = 0

    //Loop through one row by another which is selected above and stored in cursor

    WHILE @@FETCH_STATUS = 0
    BEGIN

    //If the cumulative quantity is less than user's input quantity 
    //then keep inserting into the temp table and deduct the inserted qty
    SET @cumulativeQty  = @cumulativeQty + @qty

    IF( @quantity <= @cumulativeQty)
        INSERT INTO #TmpStock VALUES(@id, @itmCode, @batchNo, @quantity, @price );
    ELSE
        INSERT INTO #TmpStock VALUES(@id, @itmCode, @batchNo, @qty, @price );
    @cumulativeQty= @quantity - @qty
    END

    FETCH NEXT
    FROM @getStock INTO @id, @itmCode, @batchNo, @qty, @price
    END


    //Closing the cursor
    CLOSE @getStock
    DEALLOCATE @getStock

//Now select your data from temp table
SELECT * FROM #TmpStock

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多