我一直在研究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表中的记录表示要为项目#1创建订单12345,数量50:
Account Item Quantity
------- ---- --------
12345 1 50
库存表显示我们手头有足够的第1项帐户12345:
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,因此您必须进行数学运算(Quantity - QuantitySold)以确定每个库存记录的剩余数量。
我几乎没有CTE。我已经找到了很多做选择的例子,你的CTE有2个部分 - 初始化部分和UNIONed的递归部分。我可以用光标写这个,但我认为可以用CTE做,我想学习如何。
如果有人可以通过CTE确认这是可能的,或者解释如何设置CTE,我会很感激。谢谢!
答案 0 :(得分:10)
--@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;