2015-11-08 2 views
-2

Я знаю, как для навигации по иерархии с connect by, как это:Reverse дерева ходьбы иерархических данных

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

Теперь я хочу, чтобы ходить по дереву в обратном направлении, используя рекурсивную with положения, но я не могу понять, как сделать это.

Пожалуйста, помогите мне.

+0

Я не уверен, я понимаю, что вы хотите, но вы пытаетесь CONNECT BY ПРИОР прил = EMPNO, и, возможно, изменить начало с выражением на подходящем? –

ответ

0

Есть два сложных момента о рекурсивном синтаксисе WITH.

Мы определяем два запроса, один из которых является якорем (значение START WITH) с UNION ALL на втором запросе, который извлекает дочерние элементы иерархического.

Другая проблема заключается в том, что мы не можем использовать LEVEL для создания заполнения в запросе CONNECT BY (потому что мы не используем CONNECT BY). Поэтому мы добавляем еще один столбец, чтобы поддерживать подсчет уровней при навигации по дереву. Обратите внимание, что я начал с нуля, так что вершина иерархии не дополняется звездочками.

Итак, вот ваш запрос повторно отливают в виде рекурсивной С утверждением:

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 
... 
Смежные вопросы