Какие столбцы образуют цикл в этой ошибке «ORA-32044: цикл обнаружен при выполнении рекурсии с запросом»? - PullRequest
1 голос
/ 10 июля 2020

У меня есть рекурсивный запрос к таблице с данными неориентированного графика. Данные представлены в виде таблицы ребер (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 (см. Скрипт) эквивалентный запрос работает правильно.)

...