Sql server 如何在CTE中查找父/子表之间的循环引用
我有一个CTE来显示两个表(父表和子表)上的依赖关系树。 存在导致循环依赖的数据问题,导致抛出最大递归级别错误。 i、 e 这些表中有数千行。如何编写查询以识别有问题的引用?或者有没有一种方法可以设置最大递归级别,一旦命中就停止CTE,而不是抛出错误…然后我可以查看结果并确定问题的子项Sql server 如何在CTE中查找父/子表之间的循环引用,sql-server,sql-server-2012,common-table-expression,Sql Server,Sql Server 2012,Common Table Expression,我有一个CTE来显示两个表(父表和子表)上的依赖关系树。 存在导致循环依赖的数据问题,导致抛出最大递归级别错误。 i、 e 这些表中有数千行。如何编写查询以识别有问题的引用?或者有没有一种方法可以设置最大递归级别,一旦命中就停止CTE,而不是抛出错误…然后我可以查看结果并确定问题的子项 WITH Recursive_CTE AS ( SELECT ItemId, CAST(ItemDescription AS varchar(100))
WITH Recursive_CTE AS
(
SELECT
ItemId,
CAST(ItemDescription AS varchar(100)) AS ItemDescription,
Qty,
CAST(ParentItemId AS SmallInt) AS ParentItemId,
CAST(ItemId AS varchar(100)) AS ParentGroupItemId,
CAST(' -' AS varchar(100)) AS LVL,
CAST(ItemId AS varchar(100)) AS HierarchyItem,
CAST(SKU AS varchar(100)) AS HierarchySKU,
CAST(ItemDescription AS varchar(100)) AS HierarchyName,
0 AS RecursionLevel
FROM dbo.vw_BOM AS child
WHERE (ParentItemId = 0)
--and ItemId = @BOMHeaderItemId
UNION ALL
SELECT
child.ItemId,
CAST(parent.LVL + child.ItemDescription AS varchar(100)) AS ItemDescription,
child.Qty,
CAST(child.ParentItemId AS SmallInt) AS ParentItemId,
parent.ParentGroupItemId,
CAST(' -' + parent.LVL AS varchar(100)) AS LVL,
CAST(parent.HierarchyItem + ':' + CAST(child.ItemId AS varchar(100)) AS varchar(100)) AS HierarchyItem,
CAST(parent.HierarchySKU + ':' + CAST(child.SKU AS varchar(100)) AS varchar(100)) AS HierarchySKU,
CAST(parent.HierarchyName + '/' + CAST(child.ItemDescription AS varchar(100)) AS varchar(100)) AS HierarchyName,
parent.RecursionLevel + 1 AS RecursionLevel
FROM Recursive_CTE AS parent INNER JOIN
dbo.vw_BOM AS child ON child.ParentItemId = parent.ItemId
)
SELECT
Recursive_CTE_1.RecursionLevel,
Recursive_CTE_1.ParentGroupItemId,
Recursive_CTE_1.ParentItemId,
Recursive_CTE_1.ItemId,
Recursive_CTE_1.Qty,
DATALENGTH(Recursive_CTE_1.LVL) AS LVLLength,
Recursive_CTE_1.ItemDescription,
item.SKU,
item.OnHandQty,
item.AllocQty,
item.AvailableQty,
item.ToBeReceivedQty,
item.AvailableWFutureQty,
Recursive_CTE_1.HierarchyItem,
Recursive_CTE_1.HierarchySKU,
Recursive_CTE_1.HierarchyName
FROM Recursive_CTE AS Recursive_CTE_1 INNER JOIN
dbo.vw_ItemInventorySummary AS item ON Recursive_CTE_1.ItemId = item.Id
ORDER BY Recursive_CTE_1.HierarchySKU
option (maxrecursion 200)
视图vw_BOM
SELECT dbo.BillOfMaterialHeader.Id AS Id, dbo.BillOfMaterialHeader.ItemId AS ItemId, 0 AS ParentItemId, FGItems.SKU AS SKU, FGItems.SKU + N': ' + FGItems.ShortDescription AS ItemDescription,
dbo.BillOfMaterialHeader.Quantity AS Qty
FROM dbo.BillOfMaterialHeader INNER JOIN
dbo.Items AS FGItems ON dbo.BillOfMaterialHeader.ItemId = FGItems.Id
UNION ALL
SELECT dbo.BillOfMaterialDetail.Id AS Id, dbo.BillOfMaterialDetail.ItemId AS ItemId, BOMHdr.ItemId AS ParentItemId, RMItems.SKU AS SKU, RMItems.SKU + N': ' + RMItems.ShortDescription AS ItemDescription,
dbo.BillOfMaterialDetail.Quantity AS Qty
FROM dbo.Items AS RMItems INNER JOIN
dbo.BillOfMaterialDetail ON RMItems.Id = dbo.BillOfMaterialDetail.ItemId INNER JOIN
dbo.BillOfMaterialHeader BOMHdr ON dbo.BillOfMaterialDetail.BillOfMaterialHeaderId = BOMHdr.Id
更新
Tab的回答为我指明了正确的方向。我在vw_BOM中使用了扁平化的父子表,然后根据选项卡的答案将其连接到自身,这表明在父表和子表中有6个项目具有相同的项目Id。
像这样:
简单自连接应该做到这一点:
SELECT * FROM MyTable t1
INNER JOIN MyTable t2
ON t1.Parent=t2.Child
AND t1.Child=t2.Parent
简单自连接应该做到这一点:
SELECT * FROM MyTable t1
INNER JOIN MyTable t2
ON t1.Parent=t2.Child
AND t1.Child=t2.Parent
您的CTE已经有一个连接了ItemID路径的层次结构。用它来确定是否已经看到了该项目,怎么样 将新列添加到CTE的锚定部分,
HasCycle=Convert(位,0)
然后在CTE的递归部分,在WHERE
子句中添加列和条件,如下所示:
...
UNION ALL
SELECT
... other columns,
HasCycle = Convert(bit,
CASE
WHEN ':' + parent.HierarchyItem + ':' LIKE
'%:' + Convert(varchar(100), child.ItemID) + ':%'
THEN 1
ELSE 0
END)
FROM
...
WHERE
...
AND parent.HasCycle = 0 --terminate after cycle is found
;
然后,您可以从递归CTE
中进行选择,其中HasCycle=1
,并在层次项目中查看开始循环的所有行及其向上的确切路径。用它来确定是否已经看到了该项目,怎么样
将新列添加到CTE的锚定部分,HasCycle=Convert(位,0)
然后在CTE的递归部分,在WHERE
子句中添加列和条件,如下所示:
...
UNION ALL
SELECT
... other columns,
HasCycle = Convert(bit,
CASE
WHEN ':' + parent.HierarchyItem + ':' LIKE
'%:' + Convert(varchar(100), child.ItemID) + ':%'
THEN 1
ELSE 0
END)
FROM
...
WHERE
...
AND parent.HasCycle = 0 --terminate after cycle is found
;
然后,您可以从递归CTE中进行选择,其中HasCycle=1
,并在层次项目中查看开始一个循环的所有行及其向上的确切路径我以前见过这些问题,并尝试一次添加一个级别的项目,忽略以前看到的问题。我以前看到过这些问题,每次只添加一个级别的项,忽略以前看到的项。可以发布表结构和当前查询吗?我无法想象你是如何从两个表的父子结构中得到最大递归错误的。@TabAlleman-Tab,我添加了表结构。让我知道这是否有意义。@ChadRichardson,当你看到这个错误时,实际上你也可以看到选择的结果,你最终会看到什么行给了你问题。@GiorgiNakeuri谢谢Giorgi,但在SSMS中这不是我的问题,结果选项卡没有任何行,消息选项卡显示最大递归错误。@ChadRichardson,可以显示查询吗?可以发布表结构和当前查询吗?我无法想象你是如何从两个表的父子结构中得到最大递归错误的。@TabAlleman-Tab,我添加了表结构。让我知道这是否有意义。@ChadRichardson,当你看到这个错误时,实际上你也可以看到选择的结果,你最终会看到什么行给了你问题。@GiorgiNakeuri谢谢Giorgi,但在SSMS中这不是我的问题,结果选项卡没有任何行,消息选项卡显示最大递归错误。@ChadRichardson,你能显示查询吗?你不能这样做。循环引用可能通过几个级别出现。没错,最初的问题让我相信只有两个级别。但它确实帮助我确定了一些问题,其中父表及其直接子表具有相同的ItemId。但可能还有其他更复杂的循环引用。你刚刚保存了我的星期五:)你不能这样做。循环引用可能通过几个级别出现。没错,最初的问题让我相信只有两个级别。但它确实帮助我确定了一些问题,其中父表及其直接子表具有相同的ItemId。但可能还有其他更复杂的循环引用。您刚刚保存了我的星期五:)