У меня есть простая структура ориентированного графа в виде таблиц в виде:
CREATE TABLE node (id NUMBER(8, 0), NAME VARCHAR2(100));
CREATE TABLE edge (parent NUMBER(8, 0), child NUMBER(8, 0));
, где node
хранит все узлы и edge
все направленные ребра от parent
до child
.Теперь мне нужно представление, которое отображает все пути от всех корней (узлов без входящих ребер) до всех других узлов в графе (включая пути нулевой длины).На графике гарантированно нет циклов.
Я использовал иерархический запрос с использованием факторинга подзапроса и получил следующее:
WITH rec_view(id, parent, lvl, root_id, path) AS (
SELECT
id
, NULL
, 1 lvl
, id root_id
, '/' || TO_CHAR(id) path
FROM node g
WHERE NOT EXISTS (SELECT 1 FROM edge h WHERE h.child = g.id)
UNION ALL
SELECT
hier.child
, prev.id
, prev.lvl + 1 lvl
, prev.root_id
, prev.path || '/' || hier.child path
FROM rec_view prev
JOIN edge hier ON prev.id = hier.parent
)
SELECT
n.id, n.NAME, v.root_id, v.lvl, v.path
FROM
rec_view v
JOIN node n ON v.id = n.id
С этими данными теста я получаю ожидаемый результат 10Строки.
INSERT INTO node VALUES (1, 'KBR');
INSERT INTO node VALUES (2, 'H');
INSERT INTO node VALUES (3, 'N');
INSERT INTO node VALUES (4, 'KBR H');
INSERT INTO node VALUES (5, 'KBR N');
INSERT INTO node VALUES (6, 'Dummy');
INSERT INTO node VALUES (7, 'Nach H');
INSERT INTO edge VALUES (1, 4);
INSERT INTO edge VALUES (1, 5);
INSERT INTO edge VALUES (2, 4);
INSERT INTO edge VALUES (3, 5);
INSERT INTO edge VALUES (4, 7);
ID Name Root Level Path
------------------------------
1 KBR 1 1 /1
2 H 2 1 /2
3 N 3 1 /3
4 KBR H 1 2 /1/4
4 KBR H 2 2 /2/4
5 KBR N 1 2 /1/5
5 KBR N 3 2 /3/5
6 Dummy 6 1 /6
7 Nach H 2 3 /2/4/7
7 Nach H 1 3 /1/4/7
Однако мне хотелось бы, чтобы запрос использовал функцию Oracle CONNECT BY
, так как я думаю, что ее легче читать и понимать, чем подфактурный факторинг, и он также является предпочтительным.путь для иерархических запросов в нашей компании.Но вопросы, которые я задаю, приводят ко многим результатам.Я получил следующее:
SELECT
parent.id id
, parent.NAME NAME
, connect_by_root parent.NAME root_id
, LEVEL lvl
, sys_connect_by_path(parent.id, '/') path
FROM
node parent
LEFT JOIN edge hier ON parent.id = hier.parent
START WITH
NOT EXISTS (SELECT 1 FROM edge h WHERE h.child = parent.id)
CONNECT BY
PRIOR hier.child = parent.id
Здесь я получаю 11 строк вместо 10, где строка с путем /1
включена дважды.
ID Name Root Level Path
-------------------------------
1 KBR 1 1 /1
4 KBR H 1 2 /1/4
7 Nach H 1 3 /1/4/7
1 KBR 1 1 /1
5 KBR N 1 2 /1/5
2 H 2 1 /2
4 KBR H 2 2 /2/4
7 Nach H 2 3 /2/4/7
3 N 3 1 /3
5 KBR N 3 2 /3/5
6 Dummy 6 1 /6
В чем проблема смой запрос и как я могу это исправить, чтобы включить только необходимые строки?