2011-10-20 27 views
9

Tôi đã nghiên cứu CTE cố gắng xác định xem có thể đệ quy cập nhật hồ sơ số lượng hàng tồn kho với số lượng đơn đặt hàng cho đến khi số lượng đơn hàng được tiêu thụ hay không.CTE - đệ quy cập nhật số lượng cho đến khi tổng số tiêu thụ

Dưới đây là các bảng và các hồ sơ:

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) 

Các bản ghi trong bảng myOrder chỉ ra rằng một trật tự sẽ được tạo cho tài khoản 12345 cho mặt hàng # 1, số lượng 50:

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

Bảng khoảng không quảng cáo cho thấy chúng tôi có nhiều mục số 1 trong tay cho tài khoản 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 

goa l là bắt đầu cắm số lượng đặt hàng là 50 vào các bản ghi kiểm kê cho đến khi tất cả 50 được tiêu thụ. Bản ghi khoảng không quảng cáo được sắp xếp theo giá trị trong cột InvDate. Bản ghi 1 có 5 số lượng còn lại (45 - 40 = 5), điều này sẽ khiến chúng tôi có thêm 45 thứ để tiêu thụ cho đơn đặt hàng. Ghi 2 có thể tiêu thụ 40. Ghi 3 có thể tiêu thụ cuối cùng 5. Khi truy vấn hoàn thành các hồ sơ tồn kho sẽ trông như thế này:

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 

Lưu ý: Các cửa hàng bảng kiểm kê QuantitySold, không QuantityRemaining, vì vậy bạn phải làm math (Số lượng - QuantitySold) để xác định số lượng vẫn còn trên mỗi bản ghi hàng tồn kho.

Tôi đã gần như không đạt được vị trí nào với CTE. Tôi đã tìm thấy rất nhiều ví dụ cho việc lựa chọn nơi bạn có 2 phần để CTE của bạn - một phần khởi tạo và phần đệ quy UNIONed với nhau. Tôi có thể viết điều này với một con trỏ, nhưng tôi nghĩ rằng nó có thể làm với một CTE và tôi muốn tìm hiểu làm thế nào.

Nếu bất cứ ai có thể xác nhận điều này là có thể với CTE hoặc giải thích cách thiết lập CTE, tôi đánh giá cao điều đó. Cảm ơn!

+3

+1 Đối với tập lệnh DDL –

+3

Tắt chủ đề, nhưng tại sao bạn sử dụng * float * để mô hình số lượng? Bạn có thực sự * muốn * để có thể có 1.47E-19 của khoản 2 còn lại trong kho không? –

+0

Damien - câu hỏi công bằng. Công ty của tôi sử dụng JDEdwards làm ERP của mình, sử dụng phao nổi cho các trường số lượng của nó. Tôi đã xây dựng những bảng này với ý nghĩ đó. Ah, cơ sở dữ liệu cũ! – Brian

Trả lời

10
[email protected] 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; 
+0

Bogdan, điều này thật tuyệt vời! Cảm ơn nhiều. Tôi cần dành chút thời gian nghiên cứu truy vấn của bạn để hiểu mọi thứ nó đang làm, nhưng nó hoạt động rất tốt. Nó thực sự mát mẻ để xem nó chạy và tiêu thụ số lượng đặt hàng đúng cách. Cảm ơn một lần nữa! – Brian

Các vấn đề liên quan