Как выполнить SQL-запрос через иерархию строк? - PullRequest
0 голосов
/ 14 марта 2019

Предположим, у меня есть следующая структура таблицы в базе данных Oracle, где PARENT ссылается на другую строку в той же таблице.

  id  | parent
  1   | null
  2   | 1
  3   | 2
  4   | 3
  5   | null
  6   | 5
  7   | 6

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

  id  | end_parent
  1   | 4
  2   | 4
  3   | 4
  4   | 4
  5   | 7
  6   | 7
  7   | 7

Ответы [ 3 ]

2 голосов
/ 15 марта 2019

Следующий запрос показывает желаемый результат, протестированный на Oracle 12c:

with
x (id, parent, origin, generation) as (
  select id, parent, id, 1 from my_table where parent is null
  union all
  select t.id, t.parent, x.origin, x.generation + 1
   from my_table t
  join x on t.parent = x.id
),
y (id, parent, generation, origin, rn) as (
  select id, parent, generation, origin, 
    row_number() over(partition by origin order by generation desc) as rn
  from x
),
z (id, origin) as (
  select id, origin from y where rn = 1
)
select x.id, z.id as end_parent
from x
join z on x.origin = z.origin
order by x.id

Результат:

ID  END_PARENT
--  ----------
1   4
2   4
3   4
4   4
5   7
6   7
7   7

Для справки вот данные, которые я использовал:

create table my_table (
  id int,
  parent int
);

insert into my_table (id, parent) values (1, null);
insert into my_table (id, parent) values (2, 1);
insert into my_table (id, parent) values (3, 2);
insert into my_table (id, parent) values (4, 3);
insert into my_table (id, parent) values (5, null);
insert into my_table (id, parent) values (6, 5);
insert into my_table (id, parent) values (7, 6);
1 голос
/ 15 марта 2019

Используйте синтаксис connect by и создайте путь, используя sys_connect_by_path.Последнее значение пути - это значение end_parent.Используйте connect_by_root, чтобы получить id корневого родителя.Исходя из этой группы, получите максимальное значение как end_parent для каждой группы.Наконец, присоедините группировку к каждой строке.

with id_paths as
(
    select
    t.id,
    substr(sys_connect_by_path(t.id,'>'),2,length(sys_connect_by_path(t.id,'>'))-1) as id_path,
    connect_by_root t.id as parent_group
    from my_table t
    connect by prior t.id = t.parent
    start with t.parent is null
),
end_parents as
(
    select 
    ip.parent_group,
    max(substr(ip.id_path, instr(ip.id_path,'>',-1)+1, length(ip.id_path))) as end_parent
    from id_paths ip
    group by ip.parent_group
)
select
ip.id,
ep.end_parent
from id_paths ip
inner join end_parents ep on ep.parent_group = ip.parent_group
order by ip.id;

Вывод

| ID | END_PARENT |
|----|------------|
|  1 |          4 |
|  2 |          4 |
|  3 |          4 |
|  4 |          4 |
|  5 |          7 |
|  6 |          7 |
|  7 |          7 |

Пример SQL Fiddle

0 голосов
/ 15 марта 2019

Основываясь на документации Oracle здесь, https://docs.oracle.com/database/121/SQLRF/queries003.htm, вы должны сделать:

SELECT      COALESCE(CONNECT_BY_ROOT parent, id) id, 
            id end_parent 
FROM        my_table
WHERE       CONNECT_BY_ISLEAF = 1
CONNECT BY  PRIOR id = parent
ORDER BY    id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...