我已经做了一些阅读,看着有类似问题的人,但只是通过使用TOP手动查找问题来缩小范围。
这是我过去为查找违规记录所做的工作。
我想知道是否有更强大的东西可以更普遍地使用。
我的查询是:
; WITH x AS ( SELECT b.ParentPartId,
b.ChildPartId,
b.ChildPartQty,
b.ConsumingWorkCenterId
FROM jbds.BoM b
UNION ALL
SELECT lb.ParentPartId,
lb.ChildPartId,
lb.ChildPartQty,
lb.ConsumingWorkCenterId
FROM jbds.BoM lb
INNER JOIN x ON lb.ParentPartId = x.ChildPartId )
SELECT *
FROM x
WHERE ConsumingWorkCenterId IS NULL
我得到的错误是:
Msg 530,Level 16,State 1,Line 1 声明终止。在语句完成之前,最大递归100已经用尽。
我知道你可以使用TOP并最终找到有问题的记录,但我想知道是否有更好的解决方案来使用TOP而不是慢慢浏览记录?
答案 0 :(得分:1)
跟踪递归级别不会解决此问题。 为了重新创建错误,我写了这段代码:
drop table #temp
GO
create table #temp (
ParentPartId int,
ChildPartId int
)
GO
truncate table #temp
GO
insert into #temp(ParentPartId,ChildPartId)
values (1,2),(2,3),(3,1)
GO
;WITH x AS (
SELECT
b.ParentPartId,
b.ChildPartId
FROM #temp b
UNION ALL
SELECT
lb.ParentPartId,
lb.ChildPartId
FROM #temp lb
INNER JOIN x
ON lb.ParentPartId = x.ChildPartId
)
SELECT
*
FROM x
如果您跟踪递归,您会发现在101级,值将为(2,3)。但这并不意味着这一行出了问题。在您的表中有一个循环的父子引用链,但查询可以在任何记录中中断,而不是逻辑上的那些记录。
要解决此问题,首先需要修复查询。你错过了"静态"的条件。 CTE的一部分(在UNION之前)。您需要将此部分中的行限制为叶子(底部 - 顶部方法)或根(上下方法),即没有其他子项(第一种方法)或没有父项(第二种方法)的行。
这样查询就不会中断,并且它不会列出将其作为父级链接的前辈的记录。此外,行不会在结果中多次列出。 然后,您必须将cte加入到原始表中,以检查来自表中的哪些记录未在cte中列出 - 这些将是您正在寻找的行。
答案 1 :(得分:1)
我的想法:禁用递归限制,添加一个跟踪递归级别的列,然后过滤level > 100
。
只是想知道是否存在SQL中其他错误的通用解决方案,例如显示错误的所有记录。
这里没有一般解决方案。查询处理器可以生成各种计划,其中许多计划没有明确的“记录顺序”或发生错误的第一点的概念。当记录通过管道时,它们通常是不完整的,并且与您所写的内容不符。
查询中的跟踪错误是一种常见的请求(想想DML中途失败 - 没有指示错误的位置)。不幸的是,这里没有好的解我最好的建议是避免查询计划中的危险模式。这说起来容易一些。