У меня есть рекурсивный запрос к таблице с данными неориентированного графика. Данные представлены в виде таблицы ребер (Oracle 11g). Рекурсивный запрос пересекает все ребра, начиная с данного ребра. Идея запроса такова: данное ребро находится на 0 -м уровне, а для n> 0 ребро находится на n -м уровне, если оно пересекается с узлом некоторого до сих пор невидимого ребра на (n-1) -м уровне.
with edges (id, a, b) as (
select 1, 'X', 'Y' from dual union
select 2, 'X', 'Y' from dual
), r (l, id, parent_a, parent_b, child_a, child_b, edge_seen) as (
select 0, id, null, null, a, b, cast(collect(id) over () as sys.ku$_objnumset)
from edges
where id = 1
union all
select r.l + 1, e.id, r.child_a, r.child_b, e.a, e.b
, r.edge_seen multiset union distinct (cast(collect(e.id) over () as sys.ku$_objnumset))
from r
join edges e on (r.child_a in (e.a, e.b) or r.child_b in (e.a, e.b))
and e.id not member of (select r.edge_seen from dual)
)
select * from r;
Запрос работал хорошо, пока не возникла эта ситуация с двумя ребрами между узлами:
+---+ 1 +---+
| |<----->| |
| X | 2 | Y |
| |<----->| |
+---+ +---+
В этом случае ребро 1 находится на 0-м уровне рекурсии (начальная строка). Я ожидал, что край 2 будет добавлен к результату на 1-м уровне рекурсии, поскольку выполняется условие соединения. Вместо этого я получаю «ORA-32044: обнаружен цикл при выполнении рекурсивного запроса».
Я знаю, что эта ошибка появляется, когда строка, вновь присоединенная к результату рекурсивного запроса, будет такой же, как какая-либо существующая строка. Я не понимаю, почему Oracle обрабатывает строку с одинаковыми идентификаторами узлов, но разными идентификаторами края как дубликаты. Добавление предложения cycle child_a, child_b set iscycle to 1 default 0
дает iscycle=1
для новой строки, добавление cycle id, child_a, child_b set iscycle to 1 default 0
дает iscycle=0
, что является правильным.
Почему возникает ошибка и как ее избежать? (Примечание в Postgres (см. Скрипт) эквивалентный запрос работает правильно.)