sql-server - CTE - 递归更新数量直到消耗总量

标签 sql-server sql-server-2005

我一直在研究 CTE,试图确定是否可以使用订单数量递归更新库存数量记录,直到订单数量被消耗。

以下是表格和记录:

CREATE TABLE [dbo].[myOrder](
  [Account] [float] NOT NULL,
  [Item] [float] NOT NULL,
  [Quantity] [float] NOT NULL
) ON [PRIMARY]

insert into dbo.myOrder values (12345, 1, 50)

CREATE TABLE [dbo].[myInventory](
  [ID] [int] IDENTITY(1,1) NOT NULL,
  [Account] [float] NOT NULL,
  [InvDate] [numeric](18, 0) NOT NULL,
  [Item] [float] NOT NULL,
  [Quantity] [float] NOT NULL,
  [QuantitySold] [float] NOT NULL
) ON [PRIMARY]

insert into dbo.myInventory values (12345, 111287, 1, 45, 40)
insert into dbo.myInventory values (12345, 111290, 1, 40, 0)
insert into dbo.myInventory values (12345, 111290, 1, 12, 0)
insert into dbo.myInventory values (12345, 111291, 1, 25, 0)

myOrder 表中的记录表明要为帐户 12345 创建项目 #1、数量 50 的订单:

Account Item Quantity 
------- ---- --------
12345   1    50

库存表显示帐户 12345 手头有大量商品 #1:

ID Account InvDate Item Quantity QuantitySold
-- ------- ------- ---- -------- ------------
1  12345   111287  1    45       40
2  12345   111290  1    40       0
3  12345   111290  1    12       0
4  12345   111291  1    25       0

目标是开始将 50 个订单数量插入库存记录中,直到 50 个全部消耗完。库存记录按 InvDate 列中的值排序。记录 1 有 5 个剩余数量 (45 - 40 = 5),这将使我们还有 45 个可供订单消耗。记录 2 可以消耗 40 个。记录 3 可以消耗最后 5 个。查询完成后,库存记录将如下所示:

ID Account InvDate Item Quantity QuantitySold
-- ------- ------- ---- -------- ------------
1  12345   111287  1    45       45
2  12345   111290  1    40       40
3  12345   111290  1    12       5
4  12345   111291  1    25       0

注意:库存表存储 QuantitySold,而不是 QuantityRemaining,因此您必须进行数学计算(数量 - QuantitySold)来确定每个库存记录的剩余数量。

我对 CTE 几乎毫无进展。我发现了很多进行选择的示例,其中 CTE 有 2 个部分 - 初始化部分和递归部分联合在一起。我可以用光标来写这个,但我认为可以用 CTE 来完成,我想了解如何操作。

如果有人可以确认 CTE 可以做到这一点或解释如何设置 CTE,我将不胜感激。谢谢!

最佳答案

--@inserted table mimics inserted virtual table from AFTER INSERT triggers on [dbo].[myOrder] table
DECLARE @inserted TABLE 
(
  [Account] [float] NOT NULL,
  [Item] [float] NOT NULL,
  [Quantity] [float] NOT NULL
);

INSERT  @inserted 
VALUES  (12345, 1, 50);

WITH CteRowNumber
AS
(
    SELECT   inv.ID
            ,inv.Account
            ,inv.Item
            ,inv.Quantity
            ,inv.QuantitySold
            ,i.Quantity QuantityOrdered
            ,ROW_NUMBER() OVER(PARTITION BY inv.Account,inv.Item ORDER BY inv.ID ASC) RowNumber
    FROM    myInventory inv
    INNER JOIN @inserted i ON inv.Account = i.Account 
    AND     inv.Item = i.Item 
    WHERE   inv.Quantity > inv.QuantitySold
),  CteRecursive
AS
(
    SELECT   a.ID
            ,a.Account
            ,a.Item
            ,a.RowNumber 
            ,CASE 
                WHEN a.Quantity - a.QuantitySold < a.QuantityOrdered THEN a.Quantity - a.QuantitySold 
                ELSE a.QuantityOrdered
            END QuantitySoldNew
            ,CASE 
                WHEN a.Quantity - a.QuantitySold < a.QuantityOrdered THEN a.Quantity - a.QuantitySold 
                ELSE a.QuantityOrdered
            END RunningTotal
    FROM    CteRowNumber a
    WHERE   a.RowNumber = 1
    UNION ALL
    SELECT   crt.ID
            ,crt.Account
            ,crt.Item
            ,crt.RowNumber
            ,CASE 
                WHEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold) < crt.QuantityOrdered THEN crt.Quantity - crt.QuantitySold
                ELSE crt.QuantityOrdered - prev.RunningTotal
            END QuantitySoldNew
            ,CASE 
                WHEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold) < crt.QuantityOrdered THEN prev.RunningTotal + (crt.Quantity - crt.QuantitySold)
                ELSE crt.QuantityOrdered
            END RunningTotal
    FROM    CteRecursive prev
    INNER JOIN CteRowNumber crt ON prev.Account = crt.Account 
    AND     prev.Item = crt.Item 
    AND     prev.RowNumber + 1 = crt.RowNumber
    WHERE   prev.RunningTotal  < crt.QuantityOrdered
)
SELECT   cte.ID
        ,cte.Account
        ,cte.Item
        ,cte.QuantitySoldNew
FROM    CteRecursive cte;
--or CteRecursive can be used to update QuantitySold column from [dbo].[myInventory] table
--UPDATE    myInventory 
--SET       QuantitySold = inv.QuantitySold + cte.QuantitySoldNew
--FROM  myInventory inv
--INNER JOIN CteRecursive cte ON inv.ID = cte.ID;

关于sql-server - CTE - 递归更新数量直到消耗总量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7843129/

相关文章:

c# - 通过打开数据库连接测试网络连接

sql-server - 如何执行包 SSIS 2008

sql - 如何从 SQL Server 上的一张表中删除 8,500,000 条记录

sql - 使用密集秩函数的第二最大值

sql - 加入另一个表中的日期时间和最新值

c# - LINQ自引用表过滤关系

sql-server - SQL Server 2008 生成脚本向导为我提供了一个导致 "unclosed quotation marks"的脚本

c# - 什么代表sql server中的double?

sql-server - IIS 服务器对并发 SQL Server 连接是否有任何限制?

php - MS SQL 2005 自动递增错误