Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Обход дерева (выбрать все связи), Oracle12с / 4 сообщений из 4, страница 1 из 1
09.10.2018, 18:32
    #39715090
Ora uSeR
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обход дерева (выбрать все связи), Oracle12с
Есть схема связи документов (входящие-исходящие письма):
img

При создании новой связи документа 1 с документом 2 в таблицу пишется 2 строки:
Код: plaintext
1.
2.
3.
PARENT_ID   ID
NULL        283
283         245

При установлении связи с документом, который уже имеет историю (проверяю наличие PARENT_ID) в таблицу пишется только одна запись:
Код: plaintext
1.
2.
PARENT_ID   ID
245         264

История связей:
обернул данные в with
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
WITH t1 AS (
	SELECT 1  AS PK, NULL AS PARENT_ID, 100 AS ID FROM dual  UNION ALL --начало истории другого документа
	SELECT 2  AS PK, NULL AS PARENT_ID, 283 AS ID FROM dual  UNION ALL
	SELECT 3  AS PK, NULL AS PARENT_ID, 284 AS ID FROM dual  UNION ALL
	SELECT 4  AS PK, NULL AS PARENT_ID, 231 AS ID FROM dual  UNION ALL
	SELECT 5  AS PK, 283  AS PARENT_ID, 245 AS ID FROM dual  UNION ALL
	SELECT 6  AS PK, 284  AS PARENT_ID, 245 AS ID FROM dual  UNION ALL
	SELECT 7  AS PK, 231  AS PARENT_ID, 247 AS ID FROM dual  UNION ALL
	SELECT 8  AS PK, 100  AS PARENT_ID, 101 AS ID FROM dual  UNION ALL  --продолжение истории другого документа
	SELECT 9  AS PK, 245  AS PARENT_ID, 264 AS ID FROM dual  UNION ALL
	SELECT 10 AS PK, 245  AS PARENT_ID, 265 AS ID FROM dual  UNION ALL
	SELECT 11 AS PK, 247  AS PARENT_ID, 265 AS ID FROM dual  UNION ALL
	SELECT 12 AS PK, 247  AS PARENT_ID, 273 AS ID FROM dual  UNION ALL
	SELECT 13 AS PK, 264  AS PARENT_ID, 252 AS ID FROM dual
)
select ID
from dual;
/




Необходимо получать ВСЮ историю связей по любому из ID документа, допустим, ID = 273.
В примере есть 2 строки ( t1.PK IN (1, 8) ) которые не должны выводиться - это история другого документа.


Немного о попытках
В части решения средствами SQL набрёл на не плохую статью с парой примеров, но применить на практике так и не получилось..


1)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
WITH
numbers ( n ) AS (
   SELECT 1 AS n
   FROM dual -- исходное множество -- одна строка
  	UNION ALL                      -- символическое «объединение» строк
   SELECT n + 1 AS n               -- рекурсия: добавок к предыдущему результату
   FROM   numbers                  -- предыдущий результат в качестве источника данных
    WHERE  n < 5                   -- если не ограничить, будет бесконечная рекурсия
)
SELECT n
FROM numbers             		   -- основной запрос
;




2)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
WITH
  anchor1234 ( n ) AS (             -- обычный
     SELECT 1 FROM dual UNION ALL
     SELECT 2 FROM dual UNION ALL
     SELECT 3 FROM dual UNION ALL
     SELECT 4 FROM dual
  )
, numbers ( n ) AS (                -- рекурсивный
     SELECT n FROM anchor1234
        UNION ALL
     SELECT n + 1 AS n
     FROM   numbers
     WHERE n < 5
  )
SELECT n FROM numbers
;
/


...
Рейтинг: 0 / 0
09.10.2018, 18:40
    #39715099
merch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обход дерева (выбрать все связи), Oracle12с
Ora uSeR,
Код: plsql
1.
connect by
...
Рейтинг: 0 / 0
09.10.2018, 19:10
    #39715111
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обход дерева (выбрать все связи), Oracle12с
Ora uSeR,

Поскольку интересуют ВСЕ связанные документы безотносительно направления связи, то это задача на ненаправленном графе.
Подобные задачи на SQL нормально не решаются.
Относительно эффективно в SQL можно решать только задачи на напраленных (где проход допустим только в направлении связи) структурах, будь то дерево или граф.

connect by может вернуть все связанные но это будет крайне избыточный перебор
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
select id, min(lvl) dist
  from (select t1.*, level lvl
          from t1
        start with id = 273
        connect by nocycle (prior parent_id in (id, parent_id) or prior id in (id, parent_id)))
        unpivot (id for type in (parent_id, id))
group by id
order by 2;

        ID       DIST
---------- ----------
       247          1
       273          1
       231          2
       265          2
       245          3
       284          4
       283          4
       264          4
       252          5

9 rows selected.


Нормальный подход в таких случаях это обход графа к глубину, который использует список посещенных узлов.

Механизм rec with тоже непригоден для поддержания списка обойденных, то есть только PL/SQL.
...
Рейтинг: 0 / 0
09.10.2018, 22:00
    #39715189
Sayan Malakshinov
Модератор форума
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обход дерева (выбрать все связи), Oracle12с
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Обход дерева (выбрать все связи), Oracle12с / 4 сообщений из 4, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]