Найти все связанные записи - PullRequest
2 голосов
/ 09 февраля 2010

У меня есть таблица заказов, которая имеет поле LinkedOrderID.

Я хотел бы создать запрос, который находит все связанные заказы и возвращает их в наборе результатов.

выберите OrderID, LinkOrderID из [Order], где LinkOrderID не является нулевым

OrderID LinkOrderID
787016 787037
787037 787786
787786 871702


Я хотел бы сохранить процесс, который возвращает следующее:
OrderID InheritanceOrder
787016 1
787037 2
787786 3
871702 4

Я также хотел бы убедиться, что у меня нет бесконечного цикла

Ответы [ 3 ]

3 голосов
/ 09 февраля 2010
DECLARE @Order TABLE (OrderID INT NOT NULL, LinkOrderID  INT NOT NULL)

INSERT
INTO    @Order
VALUES  (787016, 787037)

INSERT
INTO    @Order
VALUES  (787037, 787786)

INSERT
INTO    @Order
VALUES  (787786, 871702)

/*
INSERT
INTO    @Order
VALUES  (871702, 787016)
*/

;WITH    q (OrderId, LinkOrderId, InheritanceOrder, FirstItem) AS
        (
        SELECT  OrderID, LinkOrderId, 1, OrderID
        FROM    @Order
        WHERE   OrderID = 787786
        UNION ALL
        SELECT  o.OrderId, o.LinkOrderId, q.InheritanceOrder + 1, q.FirstItem
        FROM    q
        JOIN    @Order o
        ON      o.OrderID = q.LinkOrderId
        WHERE   o.OrderID <> q.FirstItem
        UNION ALL
        SELECT  LinkOrderId, NULL, q.InheritanceOrder + 1, q.FirstItem
        FROM    q
        WHERE   q.LinkOrderID NOT IN
                (
                SELECT  OrderID
                FROM    @Order
                )
        )
SELECT  OrderID, InheritanceOrder
FROM    q
ORDER BY
        InheritanceOrder

Предполагается, что и OrderID, и LinkOrderID являются уникальными (т. Е. Это связанный список, а не дерево).

Работает и с последней вставкой без комментариев (что делает цикл)

0 голосов
/ 09 февраля 2010

Сладкий: я нашел решение благодаря потрясающему коду Quassnoi. Я настроил его, чтобы сначала подойти к старшему родителю, а затем пройти через всех детей. Еще раз спасибо!

-- =============================================
-- Description: Gets all LinkedOrders for OrderID. 
-- It will first walk up and find oldest linked parent, and then next walk down recursively and find all children.
-- =============================================
alter PROCEDURE Order_Order_GetAllLinkedOrders
(
    @StartOrderID int
)
AS
--Step#1: find oldest parent
DECLARE @oldestParent int
;WITH    vwFirstParent (OrderId) AS 
        ( 
        SELECT  OrderID
        FROM    [Order]
        WHERE   OrderID = @StartOrderID 
        UNION ALL 
        SELECT  o.OrderId
        FROM    vwFirstParent
        JOIN    [Order] o 
        ON      o.LinkOrderID = vwFirstParent.OrderId 
        )

select @oldestParent = OrderID from vwFirstParent 

--Step#2: find all children, prevent recursion
;WITH    q (OrderId, LinkOrderId, InheritanceOrder, FirstItem) AS 
        ( 
        SELECT  OrderID, LinkOrderId, 1, OrderID 
        FROM    [Order]
        WHERE   OrderID = @oldestParent 
        UNION ALL 
        SELECT  o.OrderId, o.LinkOrderId, q.InheritanceOrder + 1, q.FirstItem 
        FROM    q 
        JOIN    [Order] o 
        ON      o.OrderID = q.LinkOrderId 
        WHERE   o.OrderID <> q.FirstItem 
        UNION ALL 
        SELECT  LinkOrderId, NULL, q.InheritanceOrder + 1, q.FirstItem 
        FROM    q
        WHERE   q.LinkOrderID NOT IN 
                ( 
                SELECT  OrderID 
                FROM    [Order]
                )
        ) 
SELECT  OrderID,LinkOrderId,  InheritanceOrder
FROM    q 
0 голосов
/ 09 февраля 2010

Чтобы проверить бесконечный цикл, есть две проверки:

Сначала убедитесь, что вы начинаете с _id, который когда-либо появлялся в LinkOrderID

select o1.OrderID from Order o1
left outer join Order o2 on o1.OrderId = o2.LinkOrderID
where o2.LinkOrderID is null;

Это даст вам список, с которого начинаются ваши связанные списки.

Затем убедитесь, что ни один из ваших _id не появится больше одного раза.

select * from {
  select LinkOrderId, count(*) as cnt from Order
} where cnt > 1;

Если эти два условия выполняются (вы начинаете с заказа, который никогда не появляется в связанном списке, и у вас нет OrderIds, которые связаны несколько раз), тогда вы не сможете есть петля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...