我有一个名为
Nodes
的表,其中包含基础文档、当前文档和目标文档:
BaseDocType . BaseDocID
DocType . DocID
TargetDocType . TargetDocID ..
我想获取任何特定节点的所有相关节点。这是我到目前为止所拥有的:
WITH CTE1 (ID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID) AS
(
SELECT
ID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID
FROM
Doc.Nodes
WHERE
DocType = 8 AND DocID = 2
UNION ALL
SELECT
a.ID, a.BaseDocType, a.BaseDocID, a.DocType, a.DocID, a.TargetDocType, a.TargetDocID
FROM
Doc.Nodes a
INNER JOIN
CTE1 b ON (a.BaseDocType = a.BaseDocType
AND a.BaseDocID = b.BaseDocID
AND a.DocType != b.DocType
AND a.DocID != b.DocID)
)
SELECT *
FROM CTE1
但是查询不起作用。我收到此错误:
消息 530,第 16 级,状态 1,第 8 行
声明终止。在语句完成之前,最大递归 100 已用完。
我该如何解决这个问题?
问题在于,锚行(ID = 2)找到了 ID = 1 的相关行,但这种关系也适用于另一个方向。因此,第 1 行会找到第 2 行,如此下去,无穷无尽。您需要某种递归终止条件。
我不确定为什么给出的模型具有基础/文档/目标关系而没有目标数据。
一些设置表值变量:
DECLARE @Nodes TABLE (ID INT, BaseDocType INT, BaseDocID INT, DocType INT, DocID INT, TargetDocType INT NULL, TargetDocID INT NULL);
INSERT INTO @Nodes
VALUES
(1, 10, 6, 100, 2034, NULL, NULL),
(2, 10, 6, 8, 2, NULL, NULL);
您可以通过以下方式传递这些信息,而不是在锚点中指定起始文档详细信息:
With CTE1 (ID, StartDocType, StartDocID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID)
As
(
Select ID, DocType, DocID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID
From @Nodes
Union All
Select a.ID, b.StartDocType, b.StartDocID, a.BaseDocType, a.BaseDocID, a.DocType, a.DocID, a.TargetDocType, a.TargetDocID
From @Nodes a
INNER JOIN CTE1 b
ON (
a.BaseDocType = b.BaseDocType
AND a.BaseDocID = b.BaseDocID
AND a.DocType != b.DocType
AND a.DocID != b.DocID
AND NOT (a.DocType = b.StartDocType AND a.DocID = b.StartDocID)
)
)
Select *
From CTE1
Where StartDocType=8 and StartDocID = 2
这很有帮助,因为递归部分可以避免重新处理起始行并从头开始循环。然而,随着数据的增加,您很可能会再次遇到同样的问题。
终止递归的最直接的方法是自己限制递归深度,通过跟踪深度并将其限制在递归部分:
With CTE1 (rlevel, ID, StartDocType, StartDocID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID)
As
(
Select 1, ID, DocType, DocID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID
From @Nodes
Union All
Select b.rlevel + 1, a.ID, b.StartDocType, b.StartDocID, a.BaseDocType, a.BaseDocID, a.DocType, a.DocID, a.TargetDocType, a.TargetDocID
From @Nodes a
INNER JOIN CTE1 b
ON (
a.BaseDocType = b.BaseDocType
AND a.BaseDocID = b.BaseDocID
AND a.DocType != b.DocType
AND a.DocID != b.DocID
)
WHERE b.rlevel < 10
)
Select DISTINCT ID, BaseDocType, BaseDocID, DocType, DocID, TargetDocType, TargetDocID
From CTE1
Where StartDocType=8 and StartDocID = 2
可能有更多更好的方法来限制递归,但这需要更多的底层数据知识。