SQL Server:遍历一个表并获取总和,直到达到阈值为止,并更新另一表中的总和

时间:2019-06-08 06:14:58

标签: sql sql-server tsql

我有两个表:

Sales表:

enter image description here

Returns表:

enter image description here

我必须遍历Sales表并基于Qty组合获取所有Material+Batch+customer的总和,直到超过Return_qty的值,然后更新{ Summed表中的{1}}值。

这是所需的输出:

enter image description here

如您所见,从Returns表到Sales 4,只有它超过了Sales_Invoice的值,它才被视为。

到目前为止我一直在尝试什么?

我尝试使用while循环遍历并计算运行总计。但它没有解决。也许方法是错误的。

任何输入都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

尝试一下:

DECLARE @Sales TABLE
(
    [Sales_Invoice] SMALLINT
   ,[Invoice_Date] DATE
   ,[Material] VARCHAR(3)
   ,[Batch] VARCHAR(2)
   ,[Customer] VARCHAR(4)
   ,[Qty] SMALLINT
);

DECLARE @Returns TABLE
(
    [Return_Invoice] SMALLINT
   ,[Invoice_Date] DATE
   ,[Material] VARCHAR(3)
   ,[Batch] VARCHAR(2)
   ,[Customer] VARCHAR(4)
   ,[Return_Qty] SMALLINT
   ,[Sales_Qty] SMALLINT
);

INSERT INTO @Sales ([Sales_Invoice], [Invoice_Date], [Material], [Batch], [Customer], [Qty])
VALUES (1, '2019-06-07', 'AB1', 'B1', 'B001', 50)
      ,(2, '2019-06-07', 'AB1', 'B1', 'B001', 20)
      ,(3, '2019-06-06', 'AB1', 'B1', 'B001', 25)
      ,(4, '2019-06-06', 'AB1', 'B1', 'B001', 11)
      ,(5, '2019-06-06', 'AB1', 'B1', 'B001', 20)
      ,(6, '2019-06-01', 'BA2', 'C1', 'Y001', 100);

INSERT INTO @Returns ([Return_Invoice], [Invoice_Date], [Material], [Batch], [Customer], [Return_Qty])
VALUES (212, '2019-06-08', 'AB1', 'B1', 'B001', 100);

WITH DataSource AS
(
    SELECT [Material], [Batch], [Customer]
          ,SUM([Qty]) OVER (PARTITION BY [Material], [Batch], [Customer] ORDER BY [Sales_Invoice] ASC) AS [Return_Qty]
    FROM @Sales
)
UPDATE @Returns
SET [Sales_Qty] = DS.[Return_Qty]
FROM @Returns R
INNER JOIN 
(
    SELECT [Material], [Batch], [Customer]
           ,MIN([Return_Qty]) AS [Return_Qty]
    FROM DataSource
    WHERE [Return_Qty] >= 100
    GROUP BY [Material], [Batch], [Customer]
) DS
    ON R.[Material] = DS.[Material]
    AND R.[Batch] = DS.[Batch]
    AND R.[Customer] = DS.[Customer];

SELECT *
FROM @Returns;

enter image description here

如果要更加动态,可以使用以下内容:

WITH DataSource AS
(
    SELECT [Material], [Batch], [Customer]
          ,SUM([Qty]) OVER (PARTITION BY [Material], [Batch], [Customer] ORDER BY [Sales_Invoice] ASC) AS [Return_Qty]
    FROM @Sales
)
UPDATE @Returns
SET [Sales_Qty] = DataSource.[Return_Qty]
FROM @Returns R
CROSS APPLY 
(
    SELECT  DS.[Material],  DS.[Batch],  DS.[Customer]
           ,MIN(DS.[Return_Qty]) AS [Return_Qty]
    FROM DataSource DS
    WHERE  DS.[Return_Qty] >= R.[Return_Qty]
        AND R.[Material] = DS.[Material]
        AND R.[Batch] = DS.[Batch]
        AND R.[Customer] = DS.[Customer]
    GROUP BY [Material], [Batch], [Customer]
) DataSource;

答案 1 :(得分:0)

您应该在帖子中真正显示while语句-您可以这样做吗?

我认为使用递归的通用表表达式对您来说是一个很好的解决方案。类似于...

;
WITH
cte1 AS
( 
SELECT
RANK() OVER
    (ORDER BY S.Material, S.Batch, S.Customer) GroupId,
RANK() OVER
    (
    PARTITION BY S.Material, S.Batch, S.Customer,
    ORDER BY S.INVOICE_Date) Seqn,
S.Material, S.Batch, S.Customer, S.qty, R.Return_qty
FROM
    Sales S
JOIN
    Returns R
    ON S.Material = R.Material AND S.Batch = R.Batch AND S.Customer = R.Customer
),
cte2 AS
( 
SELECT
GroupId, Seqn,Material, Batch, Customer, qty AS TriggeringQty, Return_qty
FROM cte1 
WHERE seqn  =1
UNION ALL
SELECT
cte1.GroupId, cte1.Seqn, cte1.Material, cte1.Batch, cte1.Customer,
    cte1.qty + cte2.qty, cte1.Return_qty
FROM cte2
    JOIN cte1
    ON cte1.GroupId = cte2.GroupID AND cte1.seqn = cte2.seqn+1
WHERE 
cte2.qty < 100 AND cte1.seqn + cte2.seqn+1 >= Return_qty )

UPDATE R
SET R.Sales_qty = cte2.triggeringqty
FROM Returns R
JOIN cte2 S ON
S.Material = R.Material AND S.Batch = R.Batch AND S.Customer = R.Customer
WHERE cte2.triggeringqty >= 100;

抱歉,我没有尝试过上述操作,因此可能无法运行,但希望您能看到发生了什么事。