【问题标题】:Find Hierarchy for each Node查找每个节点的层次结构
【发布时间】:2015-03-24 10:40:16
【问题描述】:

我正在尝试重建当前使用“RBAR”方法映射我组织的报告层次结构的存储过程。当组织较小时,这种方法效果很好,但随着组织的发展,这种方法根本无法很好地扩展。

我想做的是使用递归 CTE 来帮助加快流程。我尝试的第一步已经奏效;映射层次结构中的每个位置,因为它与第一个/顶部节点相关。

我的数据与此类似:

POSITION_NBR | REPORTS_TO |
     001           001
     002           001
     003           001
     004           002
     005           003
     006           003
     007           004

我目前的方法返回这个:

REPORTS_TO | POSITION_NBR | EMPLEVEL
    001           001          0
    001           002          1
    001           003          1
    002           004          2
    003           005          2
    003           006          2
    004           007          3

这是我的 SQL:

WITH POSN_HIERARCHY AS 
    (SELECT POS.REPORTS_TO
            ,POS.POSITION_NBR
            ,0 AS EMPLEVEL
    FROM dbo.POSITION_BASE POS
    WHERE POS.POSITION_NBR = POS.REPORTS_TO

    UNION ALL

    SELECT POS.REPORTS_TO
            ,POS.POSITION_NBR
            ,EMP.EMPLEVEL + 1
    FROM dbo.POSITION_BASE POS
    INNER JOIN POSN_HIERARCHY EMP
        ON EMP.POSITION_NBR = POS.REPORTS_TO
    WHERE POS.POSITION_NBR <> POS.REPORTS_TO)

SELECT * FROM POSN_HIERARCHY

我正在努力寻找一种方法,不仅可以找到与第一个节点相关的层次结构,还可以找到主层次结构中的 每个 层次结构。例如,我当前的 SQL 将在主要组织的结构中找到我的级别,但我也希望能够在我的经理的层次结构中看到我的级别,以及他的经理的层次结构等。

所以基本上我试图为组织中的每个经理返回一个层次结构。

我的理想输出应该是这样的:

REPORTS_TO | POSITION_NBR | EMPLEVEL
    001           001          0  
    001           002          1
    001           003          1
    001           004          2
    001           005          2
    001           006          2
    001           007          3
    002           004          1
    002           007          2
    003           005          1
    003           006          1
    004           007          1

所以输出显示了每个人相对于它上面的每个父节点的级别。 (007是001的3级,002的2级,004的1级。)

我已尝试修改锚查询以使其返回所有管理器,但这不起作用。我尝试研究 CTE 中的多个递归,但我也无法让它工作。有人可以为我指出正确的方向吗?

【问题讨论】:

  • 可以使用示例数据和预期输出编辑帖子

标签: sql-server sql-server-2008 tsql common-table-expression recursive-query


【解决方案1】:
CREATE TABLE #POSITION_BASE(POSITION_NBR VARCHAR(20), REPORTS_TO VARCHAR(20))

INSERT INTO #POSITION_BASE
SELECT '001','001'
UNION ALL
SELECT '002','001' 
UNION ALL
SELECT '003','001' 
UNION ALL
SELECT '004','002' 
UNION ALL
SELECT '005','003' 
UNION ALL
SELECT '006','003' 
UNION ALL
SELECT '007','004' 

我已经在查询中编写了逻辑

;WITH POSN_HIERARCHY AS 
(
    -- This is your first query in question. There is no changes here.
    SELECT POS.REPORTS_TO ,POS.POSITION_NBR ,0 AS EMPLEVEL
    FROM #POSITION_BASE POS    
    WHERE POS.POSITION_NBR = POS.REPORTS_TO

    UNION ALL

    SELECT POS.REPORTS_TO ,POS.POSITION_NBR ,EMP.EMPLEVEL + 1
    FROM #POSITION_BASE POS
    INNER JOIN POSN_HIERARCHY EMP
        ON EMP.POSITION_NBR = POS.REPORTS_TO
    WHERE POS.POSITION_NBR <> POS.REPORTS_TO
 )
 ,CTE2 AS
 (
     -- There will be no change to top-level parent and the child just below it.
     -- We select the children whose primary level is greater than one
     SELECT POSITION_NBR,REPORTS_TO,0 EMP
     FROM POSN_HIERARCHY     
     WHERE EMPLEVEL > 1  

     UNION ALL

    -- Finds all the parents for the children whose primary level is greater than one
    SELECT CTE.POSITION_NBR ,C.REPORTS_TO ,EMP + 1
    FROM CTE2 CTE
    INNER JOIN POSN_HIERARCHY C  ON C.POSITION_NBR = CTE.REPORTS_TO
    WHERE C.POSITION_NBR <> C.REPORTS_TO 
 )
 -- We select the top-level parent and the child just below it
 SELECT REPORTS_TO REPORTS_TO,POSITION_NBR,EMPLEVEL
 FROM POSN_HIERARCHY
 WHERE EMPLEVEL < 2

 UNION

 -- We select the children whose primary level is greater than one and its parents
 -- and increment the number by one to meet our requirement
 SELECT REPORTS_TO ,POSITION_NBR,EMP + 1 EMP
 FROM CTE2 
 OPTION(MAXRECURSION 0)

由于 SQL FIDDLE 有一些内部错误,您可以查看下图结果。

结果

【讨论】:

  • 感谢您的回答!我现在无法测试,所以稍后我会测试它并让您知道我的结果。乍一看,它看起来像我要找的东西。
  • 完美运行!完成查询需要 13 秒而不是 19 分钟以上!感谢您的帮助!
猜你喜欢
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多