【问题标题】:CTE Recursion to get hierarchy level with Empty LevelCTE 递归以获取具有空级别的层次结构级别
【发布时间】:2019-07-02 04:52:45
【问题描述】:

我在 SQL Server 2012 中有下面的表结构

INSERT INTO tblLocations (Relation, ParentID, Name, Levelnumber, Code) 
VALUES
    ('Parent', NULL, 'West',0,'X'),
    ('Child', 1, 'WA',1,'X'),
    ('Grandchild', 2, 'Seattle',2,'X'),
    ('Grandchild', 2, 'Seattle2',2,'X'),
    ('GreatGrandchild', 3, 'aa',3,'X'),
    ('GreatGrandchild', 3, 'bb',3,'X'),
    ('Parent', NULL, 'MidWest',0,'Y'),
    ('Child', 7, 'IL',1,'Y'),
    ('Grandchild', 8, 'Chicago',2,'Y'),
    ('Grandchild',8, 'Chicago1',2,'Y'),
    ('GreatGrandchild', 9, 'cc',3,'Y'),
    ('GreatGrandchild', 9, 'dd',3,'Y'),
    ('Parent', NULL, 'South',0,'Z'),
    ('Child', 13, 'TX',1,'Z'),
    ('GreatGrandchild', 14, 'ff',3,'Z'),
    ('GreatGrandchild', 14, 'ff',3,'Z'),
    ('Parent', NULL, 'North',0,'A'),
    ('Grandchild',17, 'Chicago1',2,'A'),
    ('GreatGrandchild', 18, 'ff',3,'A'),
    ('GreatGrandchild', 18, 'ff',3,'A');

正如我们所见,并非所有节点都存在某些级别。我们的要求是获得所有节点的所有级别。

例如,对于代码 X

Parent -> Child -> GrandChild --> GreatGrandchild 

层次结构在那里.. 但是对于代码 A,我们有

Parent -> GrandChild -> GreatGrandChild

代码 Z 也是如此:

Parent -> Child -> GreatGrandChild

我们的要求是,如果一个级别不存在,则应为缺少的级别填充后续级别(由级别编号标识)。我们只有 4 个关卡..

我们总是需要

Parent -> Child (if child is not there search down (Grandchild / GreatGrandchild) until data is there and populate as Child) 
       -> GrandChild - > GreatGrandChild

这是我们得到的 CTE,

WITH Hierarchy AS 
( 
    -- initialization 
    SELECT Relation, ParentID, Name, Levelnumber, Code
    FROM tblLocations
    WHERE LevelNumber = 0

    UNION ALL 

    -- recursive execution 
    SELECT S.Relation, S.ParentID,S.Name,S.Levelnumber, S.Code
    FROM tblLocations S 
    INNER JOIN tblLocations T ON T.Id = S.ParentId 
) 
SELECT * 
FROM Hierarchy 
WHERE Code = 'X' ;

我们需要它在视图中,所以不需要 T-SQL。

请指导

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    您的递归查询存在问题,因为它不是递归的。根据定义,递归查询是自引用的。根据您编写查询的方式,应该定义递归的部分只是表与自身的正常连接。

    也就是说,一切都没有丢失。这是我想出的:

    WITH Hierarchy AS 
    ( 
    --initialization 
    SELECT ID, 
        Relation, 
        ParentID, [Name], 
        Levelnumber, 
        Code, 
        1 AS [__level__],
        cast(concat('/', ID, '/') as varchar(max)) as h
    FROM tblLocations
    WHERE LevelNumber = 0
    UNION ALL 
    --recursive execution 
    SELECT child.ID,
        child.Relation,
        child.ParentID, 
        child.Name, 
        child.Levelnumber, 
        child.Code, 
        parent.[__level__] + 1,
        cast(concat(parent.h, child.ID, '/') as varchar(max)) as h
    FROM tblLocations child
    INNER JOIN Hierarchy AS parent
        ON parent.Id = child.ParentId 
    ) 
    SELECT *, 
        choose(
            Hierarchy.[__level__], 
            'Parent', 
            'Child', 
            'GrandChild', 
            'GreatGrandchild'
        ) as [DerivedRelation]
    FROM Hierarchy 
    WHERE Code = 'A' 
    order by h;
    

    实际的递归查询是相当标准的层次结构遍历的东西。为了满足您的要求,我正在计算自己在层次结构中所处位置的概念,以便我可以使用它来确定您想要显示为关系的内容。你没有说你使用的是什么版本的 SQL,所以你可能没有concat()choose()。不过没关系;它们只是 string + stringcase 语句的语法糖。

    我要在这里注意的另一件事是h 列。我已经编写了相当多的分层查询,对于它们的实际运行时执行,我更喜欢 hierarchyid。您在数据维护方面付出了一些代价,但使用它们进行查询是相当高效的(因为您可以索引层次结构并说出类似where h.IsDescendentOf(some_other_hierarchyID) 的内容。所有这一切都是说h 列是直接转换的- 如果您想朝那个方向发展,可以使用hierarchyid。

    【讨论】:

      猜你喜欢
      • 2013-11-07
      • 2018-03-30
      • 2012-12-17
      • 2023-03-24
      • 1970-01-01
      • 2018-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多