Иерархический путь Oracle в виде отдельной строки - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть таблица, как показано ниже:

ID     PARENT_ID
---    ----------  
  1     null
  2     1
  3     2
  4     2
  5     4
  6     4
  7     1
  8     7
  9     1
 10     9
 11     10
 12     9
 13     null
 14     13                 

, и я хочу запрос для получения результата, как это:

  ID | PARENT_ID
-----+-----------
   1 |   1
   2 |   1
   2 |   2
   3 |   1
   3 |   2
   3 |   3
   4 |   1
   4 |   2
   4 |   4
   5 |   1
   5 |   2
   5 |   4
   5 |   5
   ...     

Я использовал Oracle connected by root и получаю этот результат:

 ID PATH
--- -----------
 1  1
 2  1-2
 3  1-2-3
 4  1-2-4
 5  1-2-4-5
 ....

но это не то, что мне нужно.

Есть ли другой способ получить результат без подключения с помощью root (предпочтительнее в стандартном SQL), который получит тот же результат из таблицы?

Кто-нибудь может мне помочь?

Примечание: я использую базу данных Oracle

Спасибо

1 Ответ

0 голосов
/ 11 сентября 2018

Первый шаг - сделать запрос, который выдаст вам всех родителей выше определенного узла.

Вот пример такого запроса:

    select * from
(SELECT parent_id
FROM test
START WITH ID = 4
CONNECT BY ID = PRIOR PARENT_ID) temp
where parent_id is not null

UNION

select ID from test where ID = 4 ;

В приведенном выше случае мы начинаем с узла 4.

Следующим шагом будет использование этого запроса с другим запросом для получения результатов для всех узлов.

(скоро будет производить)

окончательное решение

create table test(
  id int,
  parent_id int
);

insert into test values (1, null);
insert into test values (2,1);
insert into test values (3,2);
insert into test values (4,2);

select distinct ID, parent_id from
  (
SELECT a.parent_id as aParent, b.parent_id as bParent, b.id as ID, a.id as parent_id
FROM test a, test b
START WITH a.ID = b.id
CONNECT BY a.ID = PRIOR a.PARENT_ID
  ) temp
  where not (aParent is not null AND bParent is null)
order by id, parent_id;

Оптимизированный

  SELECT distinct b.id as ID, a.id as parent_id
    FROM test a, test b
     where not (a.parent_id is not null and b.parent_id is null )
    START WITH a.ID = b.id
    CONNECT BY a.ID = PRIOR a.PARENT_ID order by id, parent_id;;

Упрощение булевой алгебры

   SELECT distinct
  findNodesAboveMe.id as ID,
  pathFollowing.id    as parent_id
FROM
  test pathFollowing,
  test findNodesAboveMe
where
  pathFollowing.parent_id is null
  OR findNodesAboveMe.parent_id is not null START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
order by
  id,
  parent_id;

Исправление для нулевых родителей

select id, parent_id from
  (
    (SELECT DISTINCT
       findNodesAboveMe.id              AS ID,
       CASE WHEN pathFollowing.parent_id IS NULL
         THEN pathFollowing.id
       ELSE pathFollowing.parent_id END AS parent_id
     FROM
       test pathFollowing,
       test findNodesAboveMe
     WHERE
       findNodesAboveMe.parent_id IS NOT NULL
     START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
    )
    UNION
    SELECT
      id,
      id AS parent_id
    FROM test
  ) order by id, parent_id
;

Обновление

select
  distinct bid as ID, aid as parent_id

  from
    (
      SELECT DISTINCT
        a.id as aid,
        a.parent_id as aparentid,
        b.id as bid,
        b.parent_id as bparentid,

        ltrim(sys_connect_by_path(a.id, ','), ',') AS pth
      FROM test a, test b
      WHERE NOT
            (a.parent_id IS NOT NULL AND b.parent_id IS NULL)
      START WITH a.ID = b.id
      CONNECT BY a.ID = PRIOR a.PARENT_ID
    ) temp
  where ( pth like bid or  pth like bid || ','|| bparentid || '%' )
 order by ID, parent_id;
...