Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Обход дерева (выбрать все связи), Oracle12с  [new]
Ora uSeR
Member

Откуда:
Сообщений: 1
Есть схема связи документов (входящие-исходящие письма):
+ img
Картинка с другого сайта.

При создании новой связи документа 1 с документом 2 в таблицу пишется 2 строки:

PARENT_ID ID
NULL 283
283 245

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

PARENT_ID ID
245 264

История связей:
+ обернул данные в with

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)
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)
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
;
/

9 окт 18, 18:32    [21699597]     Ответить | Цитировать Сообщить модератору
 Re: Обход дерева (выбрать все связи), Oracle12с  [new]
merch
Member

Откуда:
Сообщений: 127
Ora uSeR,
connect by
9 окт 18, 18:40    [21699611]     Ответить | Цитировать Сообщить модератору
 Re: Обход дерева (выбрать все связи), Oracle12с  [new]
dbms_photoshop
Member

Откуда: sqlmdx.net
Сообщений: 5149
Ora uSeR,

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

connect by может вернуть все связанные но это будет крайне избыточный перебор
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.
9 окт 18, 19:10    [21699645]     Ответить | Цитировать Сообщить модератору
 Re: Обход дерева (выбрать все связи), Oracle12с  [new]
xtender
Member

Откуда: Мск
Сообщений: 4966
Ora uSeR,

http://orasql.org/2017/09/29/connected-components/
9 окт 18, 22:00    [21699791]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить