Первый шаг - сделать запрос, который выдаст вам всех родителей выше определенного узла.
Вот пример такого запроса:
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;