Как выполнить вложенные циклы в SQL? - PullRequest
0 голосов
/ 05 мая 2019

Я пытаюсь подсчитать количество предметов, где каждый предмет может иметь детей, чье количество также будет включено. Дерево не имеет конкретного ограничения по глубине, поэтому я должен иметь возможность зацикливаться, пока не найдены дочерние элементы для элемента, а затем перейти к следующему элементу на этом уровне и продолжить вычисление суммы количества элементов.

Я могу рассчитать сумму элементов на начальном уровне, используя следующий SQL, но я не знаю, как правильно выполнить цикл для добавления количеств для любых дочерних элементов каждого элемента:

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

Мои таблицы составлены таким образом, что у единицы доставки есть идентификатор и идентификатор родителя Сумма 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.

Я должен в итоге получить СУММУ всех количеств ветвей дерева, где каждая ветвь начинается с идентификатора во входном списке.

Пример списка ввода:

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 голосов
/ 05 мая 2019

Как уже упоминалось, здесь вы хотите получить рекурсивное общее табличное выражение (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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...