Вы можете использовать два иерархических запроса, хотя, похоже, должен быть способ еще больше упростить это:
select employee_id,
last_name,
ltrim(sys_connect_by_path(rn, '.'), '.') as rnum
from (
select employee_id, manager_id, last_name,
dense_rank() over (partition by level, manager_id order by last_name) as rn
from employees
start with manager_id is null
connect by manager_id = prior employee_id
)
start with manager_id is null
connect by manager_id = prior employee_id
order by employee_id;
, что с подмножеством идентификаторов в вашей скрипте SQL (что для MySQL скореечем Oracle, как ни странно) дает:
EMPLOYEE_ID LAST_NAME RNUM
----------- ------------------------- ------------------------------
100 King 1
102 De Haan 1.2
103 Hunold 1.2.1
104 Ernst 1.2.1.2
105 Austin 1.2.1.1
106 Pataballa 1.2.1.4
107 Lorentz 1.2.1.3
147 Errazuriz 1.3
148 Cambrault 1.1
166 Ande 1.3.1
167 Banda 1.3.2
168 Ozer 1.1.5
169 Bloom 1.1.2
170 Fox 1.1.3
171 Smith 1.1.6
172 Bates 1.1.1
173 Kumar 1.1.4
или с полной таблицей схемы HR по умолчанию дает:
EMPLOYEE_ID LAST_NAME RNUM
----------- ------------------------- ------------------------------
100 King 1
101 Kochhar 1.7
102 De Haan 1.2
103 Hunold 1.2.1
104 Ernst 1.2.1.2
105 Austin 1.2.1.1
106 Pataballa 1.2.1.4
107 Lorentz 1.2.1.3
108 Greenberg 1.7.2
109 Faviet 1.7.2.2
110 Chen 1.7.2.1
...
204 Baer 1.7.1
205 Higgins 1.7.3
206 Gietz 1.7.3.1
107 rows selected.
В любом случае это не совсем соответствует предложенному вами результату;например, есть только один менеджер высшего уровня, а не пять ожидаемых в вашем выходном примере.
Если вы используете 11gR2, вы можете вместо этого использовать рекурсивный CTE, который, возможно, легче отслеживать и (для меня в любом случае, в любом случае)) более интуитивно понятный:
with rcte (employee_id, last_name, rnum) as (
select e.employee_id, e.last_name,
to_char(dense_rank() over (order by e.last_name))
from employees e
where manager_id is null
union all
select e.employee_id, e.last_name,
r.rnum ||'.'|| dense_rank() over (partition by r.rnum order by e.last_name)
from rcte r
join employees e on e.manager_id = r.employee_id
)
select *
from rcte
order by employee_id;
, который дает те же результаты.
Я догадался, что вы обрабатываете каждый уровень в порядке фамилии, но вы можете настроить, если это не такчто вы на самом деле хотите.
Если вы хотите упорядочить результат по этим уровням, тогда методом грубой силы можно токенизировать сгенерированное значение rnum
:
...
order by
to_number(regexp_substr(rnum, '[^.]+', 1, 1)) nulls first,
to_number(regexp_substr(rnum, '[^.]+', 1, 2)) nulls first,
to_number(regexp_substr(rnum, '[^.]+', 1, 3)) nulls first,
to_number(regexp_substr(rnum, '[^.]+', 1, 4)) nulls first;
и с вашим меньшимснова подмножество, которое теперь дает:
EMPLOYEE_ID LAST_NAME RNUM
----------- ------------------------- ------------------------------
100 King 1
148 Cambrault 1.1
172 Bates 1.1.1
169 Bloom 1.1.2
170 Fox 1.1.3
173 Kumar 1.1.4
168 Ozer 1.1.5
171 Smith 1.1.6
102 De Haan 1.2
103 Hunold 1.2.1
105 Austin 1.2.1.1
104 Ernst 1.2.1.2
107 Lorentz 1.2.1.3
106 Pataballa 1.2.1.4
147 Errazuriz 1.3
166 Ande 1.3.1
167 Banda 1.3.2
db <> скрипка