分层数据的反向树遍历

时间:2015-11-08 20:04:38

标签: sql oracle hierarchical-data

我知道如何使用connect by像这样导航层次结构:

SELECT RPAD ('*', 2 * LEVEL, '*') || ename ename, empno 
FROM scott.emp 
START WITH mgr IS NULL 
CONNECT BY PRIOR empno = mgr 

现在我想使用递归with子句向后走树,但我无法弄清楚如何这样做。

请帮助我。

1 个答案:

答案 0 :(得分:0)

关于递归WITH语法有两个棘手的问题。

我们在第二个查询中定义了两个查询,一个作为锚点(START WITH值)和一个UNION ALL,它检索层次结构的子节点。

另一个问题是我们不能使用LEVEL在CONNECT BY查询中生成填充(因为我们没有使用CONNECT BY)。因此,我们添加另一列以在我们导航树时保持级别的计数。请注意,我从0开始,因此层次结构的顶部没有用星号填充。

因此,这是您的查询重新转换为递归的WITH语句:

with e1 (ename, empno, lvl) 
        as ( select ename
                    , empno
                    , 0 as lvl
             from emp
             where mgr is null
             union all
             select  e2.ename 
                    , e2.empno 
                    , e1.lvl + 1
              from emp e2, e1
                where e2.mgr = e1.empno )
search depth first by empno set empno_order
select rpad ('*', 2 * e1.lvl, '*') || e1.ename ename
       , e1.empno
from e1
order by empno_order
;

search depth first子句保证结果集在显示兄弟节点之前显示给定节点的所有子节点。 (search breadth first将列出所有兄弟姐妹然后从层次结构的下一级开始。)

现在,要做一个反向树步行,我们需要从不是经理的员工开始。因为我们正在检查空值,所以我们需要使用NOT EXISTS而不是NOT IN。否则查询几乎相同;我选择显示MGR而不是EMPNO,但您可能更愿意还原。

with e1 (ename, mgr, lvl) 
        as ( select e.ename
                    , e.mgr
                    , 0 as lvl
             from emp e
             where not exists ( select null 
                                from emp x
                                where x.mgr = e.empno)
             union all
             select  e2.ename 
                    , e2.mgr 
                    , e1.lvl + 1
              from emp e2, e1
                where e2.empno = e1.mgr )
search depth first by mgr set mgr_order
select rpad ('*', 2 * e1.lvl, '*') || e1.ename ename
       , e1.mgr
from e1
order by mgr_order
;

以下是此查询的示例输出:

ENAME                                 MGR
------------------------------ ----------
ALLEN                                7698
**BLAKE                              7839
****KING
JAMES                                7698
**BLAKE                              7839
****KING
MARTIN                               7698
**BLAKE                              7839
****KING
TURNER                               7698
...