我有一个Order表,它有一个LinkedOrderID字段。
我想构建一个查找所有链接订单的查询,并在结果集中返回它们。
从[Order]中选择OrderID,LinkOrderID,其中LinkOrderID不为空
订单ID LinkOrderID
787016 787037
787037 787786
787786 871702
我想要一个返回以下内容的存储过程:
OrderID InheritanceOrder
787016 1
787037 2
787786 3
871702 4
我还想确保我没有无限循环
答案 0 :(得分:3)
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
都是唯一的(即,它是链接列表,而不是树)。
也可以使用最后一个未注释的插入(这会产生一个循环)
答案 1 :(得分:0)
要检查无限循环,有两项检查:
首先,请确保以LinkOrderID
select o1.OrderID from Order o1
left outer join Order o2 on o1.OrderId = o2.LinkOrderID
where o2.LinkOrderID is null;
这将为您提供一个列表,它是链接列表的开头。
然后,确保你的所有_ids都不会出现过多次。
select * from {
select LinkOrderId, count(*) as cnt from Order
} where cnt > 1;
如果这两个条件属实(您从一个从未出现在链接列表中的订单开始,并且您没有多次链接的OrderIds),那么 不能 < / strong>有一个循环。
答案 2 :(得分:0)
Sweet:我发现这个解决方案归功于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