1

我遇到了以下过度递归问题,并且正在努力想象哪里出了问题

我的数据如下:

Hierarchy       Id      RecNo   ParentRecord   Data
Mike            1       100     
Mike:b1         1       101     100            This One
Mike:b1:c1      1       102     101         
Mike:b1:c1:d    1       103     102
Mike:b1:c2:e    1       104     102
Mike:b2         1       110     100
Dave            2       200     
Dave:b4         2       201     200
Dave:b4:c3      2       202     201

我有以下 UDF

CREATE FUNCTION [dbo].[IsParent] ( @HierarchyA VARCHAR(1000), @HierarchyB VARCHAR(1000) )
RETURNS INT
AS
BEGIN
DECLARE @ret INT
If dbo.CountChar(@HierarchyA, ':') >= dbo.Ifx_CountChar(@HierarchyB, ':')
    SET @ret = 0
ELSE IF LEFT(@HierarchyB, LEN(@HierarchyA + ':')) = @HierarchyA + ':'
    SET @ret = 1
ELSE
    SET @ret = 0        
RETURN @ret
END

CREATE FUNCTION [dbo].[CountChar] ( @Input VARCHAR(1000), @SearchChar CHAR(1) )
RETURNS INT
BEGIN
    RETURN (LEN(@Input) - LEN(REPLACE(@Input, @SearchChar, '')))
END

我的 CTE 如下:

With Trees (Id, Hierachy, RecNo, Tier)
AS
(
    SELECT Id, Hierachy, RecNo, dbo.CountChar(Hierachy, ':') as Tier
    FROM MyData 
    WHERE Data="This One"

UNION ALL   

    SELECT e.Id, e.Hierachy, e.RecNo, dbo.CountChar(e.Hierachy, ':') 
    FROM 
        MyData e 
    INNER JOIN 
        (SELECT Id, Hierachy, RecNo FROM Trees) s 
    ON e.Id = s.Id
    WHERE dbo.IsParent(s.Hierachy,e.Hierachy) = 1   
    OR dbo.IsParent(e.Hierachy,s.Hierachy) = 1  
)

SELECT * FROM Trees
ORDER BY Hierachy, Tier

如果我单独使用任何一个 OR 子句,cte 工作正常,但是当我同时使用它们时,它会因超出最大递归错误而崩溃。

我正在尝试根据某些数据的值重建层次结构。因此,在找到具有特定数据值的行后,我想根据层次结构字段指定的层次关系识别该行的所有父项和子项。所以在上面的例子中,我想检索以下与 Mike 相关的行

Mike            1       100     
Mike:b1         1       101     100            This One
Mike:b1:c1      1       102     101         
Mike:b1:c1:d    1       103     102
Mike:b1:c2:e    1       104     102

我想知道是否有人可以

  1. 解释如何避免过度递归问题
  2. 建议以这种方式使用 Hierarchy(使用部分字符串匹配)是否(或不)比使用 RecNo/ParentRecord 关系在这种情况下遍历树更可取

非常感谢 IA

小号

4

1 回答 1

1

在不更改架构的约束下,这就是我的建议:

  • 使用两个 CTE,一个上树,一个下树
  • 在 CTE 的递归部分中,一次只移动一个级别,而不是尝试在任意距离检查祖先/后代状态。

最后我会注意到,目前您的表格有两种建模树的方法;如果他们不同意,哪个会赢?

现在到代码

样本数据:

DECLARE @Data TABLE (
    Hierarchy nvarchar(max),
    Id int,
    RecNo int,
    ParentRecord int,
    Data nvarchar(max)
);

INSERT @Data VALUES
('Mike',            1,       100,     NULL,NULL),
('Mike:b1',         1,       101,     100,            'This One'),
('Mike:b1:c1',      1,       102,     101      ,NULL)   ,
('Mike:b1:c1:d',    1,       103,     102,NULL),
('Mike:b1:c2:e',    1,       104,     102,NULL),
('Mike:b2',         1,       110,     100,NULL),
('Dave',            2,       200,     NULL,NULL),
('Dave:b4',         2,       201,     200,NULL),
('Dave:b4:c3',      2,       202,     201,NULL);

询问:

WITH SelfAndAncestors AS
(
    -- anchor
    SELECT * FROM @Data WHERE Data = 'This One'
    UNION ALL
    -- recursive part
    SELECT Parent.* FROM @Data Parent 
        INNER JOIN SelfAndAncestors Child
        ON Parent.RecNo = Child.ParentRecord
),
SelfAndDescendants AS
(
    -- anchor
    SELECT * FROM @Data WHERE Data = 'This One'
    UNION ALL
    -- recursive part
    SELECT Child.* FROM @Data Child
        INNER JOIN SelfAndDescendants Parent
        ON Parent.RecNo = Child.ParentRecord
)
SELECT * FROM SelfAndAncestors 
UNION 
SELECT * FROM SelfAndDescendants
ORDER BY Hierarchy

为方便起见,两个 CTE 都包含感兴趣的记录 ( This One),并UNION删除了重复项。

结果:

Hierarchy              Id          RecNo       ParentRecord Data
---------------------- ----------- ----------- ------------ ---------------------
Mike                   1           100         NULL         NULL
Mike:b1                1           101         100          This One
Mike:b1:c1             1           102         101          NULL
Mike:b1:c1:d           1           103         102          NULL
Mike:b1:c2:e           1           104         102          NULL
于 2013-09-06T09:36:56.740 回答