如何在SQL中执行嵌套循环?

时间:2019-05-05 17:17:39

标签: sql sql-server tsql stored-procedures

我正在尝试计算商品的数量,其中每个商品可能都有孩子,这些孩子的人数也将包括在内。这棵树的深度没有具体限制,因此我需要能够循环播放,直到没有找到子项为止,然后转到该级别的下一个项并继续计算项计数之和。

我可以使用以下SQL来计算初始级别的项目总和,但是我对如何正确循环以添加每个项目的任何子项的数量不知所措:

SELECT SUM(ShippingUnitMaterial.Quantity)
       FROM ShippingUnitMaterial
       WHERE ShippingUnitMaterial.ShippingUnitID =                           
             ShippingUnit.ShippingUnitID)
       AS TotalMaterialQty

我的表被构造成一个装运单元,因此具有一个ID和一个ParentID。如前面的SUM语句所示计算数量SUM,然后我需要执行查找并为每个孩子执行相同的计算(添加到主SUM中)。

用伪代码将是:

LOOP
FOR EACH ShippingUnitID in an input list of ShippingUnitIDs
    SUM the ShippingUnitMaterial.Quantity for all records in ShippingUnitMaterial
    WHERE ShippingUnitMaterial.ShippingUnitID == ShippingUnit.ShippingUnitID
    create a list, ChildList, of all ShippingUnitIDs where the ParentID == ShippingUnit.ShippingUnitID
    IF ChildList is not empty, call MAIN LOOP with the list
END LOOP

我可以很容易地用C#编写代码,但是在复制SQL逻辑时遇到了麻烦。

我应该以所有分支的总和结尾,其中每个分支在输入列表中以ID开头。

样本输入列表:

3093, 3096

ShippingUnitMaterial表的样本数据:

ShippingUnitMaterialID  DeliveryID  ShippingUnitID  Quantity
4204                    1           3093            1
4205                    1           3094            2
4207                    3           3099            7
4208                    3           3096            4

ShippingUnitSU表的样本数据:

ShippingUnitSUID    DeliveryID  ParentShippingUnitID    ShippingUnitID
205                 2391        3097                    3093
206                 2391        3093                    3094
207                 2391        3093                    3099
208                 2391        3313                    3096

所需的输出将是:

For input 3093, 10
For input 3096, 4

1 个答案:

答案 0 :(得分:0)

正如其他人提到的那样,这里您想要的是递归公用表表达式(rCTE),以通过父子关系进行递归,然后进行汇总。结果如下:

CREATE TABLE dbo.ShippingUnitMaterial (ShippingUnitMaterialID int,
                                       DeliveryID int,
                                       ShippingUnitID int,
                                       Quantity int);

CREATE TABLE dbo.ShippingUnitSU (ShippingUnitSUID int,
                                 DeliveryID int,
                                 ParentShippingUnitID int,
                                 ShippingUnitID int);

INSERT INTO dbo.ShippingUnitMaterial
VALUES (4204,1,3093,1),
       (4205,1,3094,2),
       (4207,3,3099,7),
       (4208,3,3096,4);

INSERT INTO dbo.ShippingUnitSU
VALUES (205,2391,3097,3093),
       (206,2391,3093,3094),
       (207,2391,3093,3099),
       (208,2391,3313,3096);
GO

WITH Shippings AS (
    SELECT SU.ShippingUnitID AS StartID,
           NULL AS ParentID,
           SU.ShippingUnitID AS ShippingID
    FROM dbo.ShippingUnitSU SU
    WHERE SU.ShippingUnitID IN (3093,3096)
    UNION ALL
    SELECT S.StartID,
           S.ShippingID AS ParentID,
           SU.ShippingUnitID AS ShippingID
    FROM dbo.ShippingUnitSU SU
         JOIN Shippings S ON SU.ParentShippingUnitID = S.ShippingID)
SELECT S.StartID,
       SUM(UM.Quantity) AS TotalQuantity
FROM Shippings S
     JOIN dbo.ShippingUnitMaterial UM ON S.ShippingID = UM.ShippingUnitID
GROUP BY S.StartID;


GO

DROP TABLE dbo.ShippingUnitSU;
DROP TABLE dbo.ShippingUnitMaterial;