#oracle #tree #hierarchical-data #connect-by
#Oracle #дерево #иерархия-данные #подключение по
Вопрос:
У меня есть таблица users
, представляющая иерархическое дерево следующим образом:
Столбец | Тип | Комментарий |
---|---|---|
идентификатор пользователя | целое число | последовательность |
user_type | целое число | 1 для группы пользователей 2 для обычного пользователя |
group_id | целое число | Ссылка на пользователя в той же таблице с user_type = 1 |
имя_пользователя | varchar(xxx) |
Столбец group_id ссылается на другой user_id, так что группы и пользователи хранятся в одной таблице.
Идентификатор главной группы равен 0.
Вот так:
идентификатор пользователя | user_type | group_id | имя_пользователя |
---|---|---|---|
0 | 1 | null | «Все пользователи» |
5 | 2 | 0 | ‘ПОЛЬЗОВАТЕЛЬ1’ |
6 | 2 | 0 | ‘USER2’ |
11 | 1 | 0 | ‘SUBGROUP1’ |
12 | 1 | 11 | ‘SUBGROUP2’ |
13 | 2 | 12 | ‘ПОЛЬЗОВАТЕЛЬ3’ |
20 | 1 | 0 | ‘SUBGROUP3’ |
21 | 2 | 20 | ‘ПОЛЬЗОВАТЕЛЬ4’ |
Обратите внимание, что:
- В user_id могут быть пробелы.
- Группа может содержать ничего или любое количество групп или пользователей.
Мне уже удалось получить полное дерево с правильным отступом и отсортированным, используя connect by
инструкцию oracle.
Это не мой вопрос здесь.
Мой вопрос:
Учитывая идентификатор пользователя для запроса, как просмотреть дерево до главной группы «Все пользователи» и вывести в результате полный путь от листа до главной группы?
Пример 1: Я запускаю запрос для USER1, мне нужен следующий вывод:
All Users
- USER1
Пример 2: Я запускаю тот же запрос для USER3, мне нужен следующий вывод:
All Users
- SUBGROUP1
-- SUBGROUP2
--- USER3
Я надеюсь, что кто-нибудь может мне помочь в этом.
Для получения дополнительной информации я отправляю запрос для получения полного дерева, чтобы вы могли увидеть использование connect by
и start with
. Я уверен, что этот запрос близок к тому, который я хочу, но мои попытки никогда не дают желаемого результата.
select
lpad('-', (level - 1) * 2, ' ') || u.user_name as padded_name,
u.userid,
u.user_group,
u.user_type,
level
from users u
connect by prior u.user_id = u.group_id
start with u.user_id = 0
order siblings by upper(u.user_name);
Ответ №1:
Вы могли бы использовать connect by
для перемещения в противоположном направлении. Тогда level
, конечно, тоже будет наоборот. Итак, чтобы получить результаты в правильном порядке и с правильным отступом, создайте другой запрос на основе этих результатов, который будет использоваться row_number()
для определения отступа:
with base as (
select
u.user_name,
u.user_id,
u.group_id,
u.user_type,
level as lvl
from users u
connect by prior u.group_id = u.user_id
start with u.user_id = 13
)
select
lpad('-', (row_number() over (order by lvl desc) - 1) * 2, ' ') || base.user_name
as padded_name,
user_id,
group_id,
user_type
from base
order by lvl desc;