SQL - 映射 Parent/Child 层次结构

TSQL - Mapping Parent/Child Hierarchy

Sample Data:

DECLARE @Hierarchy TABLE
    (
        [ParentId] INT
      , [ChildId]  INT
    ) ;

INSERT INTO @Hierarchy
VALUES
    ( 1, 2 )
  , ( 1, 3 )
  , ( 2, 4 )
  , ( 3, 5 )
  , ( 4, 3 )
  , ( 4, 6 )
  , ( 5, 6 )
  , ( 7, 3 ) ;

Current Query:

; WITH CTE AS
    (
        SELECT  [ParentId]
              , [ChildId]
              , 1 AS [Level]
              , CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) )  AS [Path]
        FROM    @Hierarchy
        UNION ALL
        SELECT  [C].[ParentId]
              , [T].[ChildId]
              , [C].[Level] + 1
              , CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
        FROM    CTE AS [C]
        JOIN    @Hierarchy AS [T]
        ON      [C].[ChildId] = [T].[ParentId]
    )
SELECT      *
FROM        CTE
ORDER BY    [ParentId]
          , [Level]
          , [ChildId] ;

Goal:

  1. 将共享“路径”的级别明显分组在一起
  2. 找到共享“路径”的最浅层和最深层

Expected Output:

注意:手动插入末尾带有橙色突出显示的记录以显示我所期望的,但还没有弄清楚。

组:基本上是遵循相同路径的每个“组”节点的“密集排列”。我认为如果您查看上图中 Group 的值并将其与 Level 和 Path 字段的数据相关联,它会更有意义。

IsShallowest:第 1 级(现在有人提出来了,我明白了)。只需要弄清楚如何导出那些丢失的(重复的)记录

IsDeepest:组内的最大级别。

一旦弄清楚“组”逻辑并添加丢失的(重复的)记录,就很容易弄清楚 IsShallowest 和 IsDeepest。

请检查此解决方案。它提供了请求的解决方案,除了添加需要更多信息的额外行

;WITH CTE AS (
    SELECT  
        [ParentId]
        , [ChildId]
        , 1 AS [Level]
        , CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) )  AS [Path]
        , MyGroup1 = ROW_NUMBER() OVER(ORDER BY [ParentId])
        , MyGroup2 = ROW_NUMBER() OVER(ORDER BY [ParentId])
    FROM Hierarchy
    UNION ALL
    SELECT  
        [C].[ParentId]
        , [T].[ChildId]
        , [C].[Level] + 1
        , CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
        , MyGroup1 = C.MyGroup1
        , MyGroup2 = [C].[MyGroup1] + ROW_NUMBER() OVER(ORDER BY [T].[ParentId]) - 1
    FROM CTE AS [C]
    JOIN Hierarchy AS [T] ON [C].[ChildId] = [T].[ParentId]
)
, MyCTE2 as (
    SELECT
        [ParentId]
        , [ChildId]
        , [Level]
        , [Path]
        -- un-comment bellow 2 rows to see the logic
        --, MyGroup1
        --, MyGroup2
        , MyGroup = DENSE_RANK() OVER (ORDER BY MyGroup1, MyGroup2)
    FROM CTE
),
MyCTE3 as (
    SELECT
        [ParentId]
        , [ChildId]
        , [Level]
        , [Path]
        , MyGroup 
        , shallowest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path]) 
        , deepest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path] DESC) 
    FROM MyCTE2
)
SELECT
    [ParentId]
    , [ChildId]
    , [Level]
    , [Path]
    , MyGroup 
    , ISshallowest = CASE WHEN shallowest = 1 then 1 else 0 END
    , Isdeepest = CASE WHEN deepest = 1 then 1 else 0 END
FROM MyCTE3
ORDER BY
    --[Path]
    [ParentId]
    , [Level]
    , [ChildId];