SQL Multi-Условная рекурсия CTE - PullRequest
11 голосов
/ 05 августа 2011

В базе данных у меня есть 2 следующих фрагмента информации для каждого идентификатора.Компания, которая их контролирует, и компании, в которых у них есть небольшие кусочки контроля.

Нечто подобное, 2 таблицы (игнорируя некоторые уникальные идентификаторы):

организации

orgid | org_immediate_parent_orgid
1     | 2
2     | 2
3     | 1
5     | 4

Отношение orgid -> org_immediate_parent_orgid означает, что компания имеет родителя.Для меня это относится только к org_immediate_parent_orgid -> orgid, материнская компания которого имеет в качестве дочернего предприятия

org_affiliations

orgid | affiliated_orgid
2     | 3
2     | 5
4     | 1
1     | 5

orgid -> affiliated_orgid - Компания имеет филиал

Визуальное представление должно выглядеть примерно так:

Database representation

На красных отношениях от организаций , на синих отношениях org_affiliations .

Если хотите, чтобы все компании, принадлежащие 2 (или дочернему сыну 2), имели какое-то участие в них:

select m.org_immediate_parent_orgid
,m.orgid
from oa.organizations m
where m.org_immediate_parent_orgid is not null
start with m.orgid in (Identifiers)
connect by nocycle prior  m.orgid=m.org_immediate_parent_orgid

возвращает

org_immediate_parent_orgid| orgid
1                         | 2
2                         | 2
3                         | 1

ЕслиХотите, чтобы все компании были 2 (или дочерним сыном 2) имеет какое-то участие в них их:

select aff.orgid,aff.affiliated_orgid
from oa.org_affiliations aff
where aff.affiliated_orgid is not null
start with aff.orgid in(Identifiers)
connect by nocycle prior  aff.affiliated_orgid =aff.orgid

возврат

orgid | affiliated_orgid
2     | 3
2     | 5

Итак, из всех возможных отношений:

  • Aff -> Aff
  • Aff -> Sub
  • Sub -> Aff
  • Sub -> Sub

Я нахожу только Sub -> Sub (дочерние компании дочерних компаний), отношения (2 -> 1 и отношения 1 -> 3) и Aff -> Aff, отношения (2 -> 3 и отношения 2 -> 5),Кроме того, он требует от меня 2 отдельных запросов.

Как я могу получить все возможные отношения в одном рекурсивном запросе?

Если я передам идентификатор 2, то будет возможно следующее возвращение:

Relation | Loop| orgid | children
Sub      | 1   | 2     |2
Sub      | 1   | 2     |1
Aff      | 1   | 2     |3
Aff      | 1   | 2     |5
Sub      | 2   | 1     |3
Aff      | 2   | 1     |5

В каждом цикле проверял бы подписчики и филиалы для каждого идентификатора.Повторите для новых детей.

Есть идеи, как к этому подойти?

TL: DR: 2 таблицы (дочерние компании \ филиалы), 2 запроса.хочу один запрос, где от компании я нахожу все дочерние и зависимые компании и все возможные комбинации дочерних компаний.Окончательный ожидаемый результат, просто следуйте представлению изображения.

Редактировать: Как прокомментировал Крейг, я исправил вывод.

Редактировать 2: СледующийКрэйг и Боб Джарвис оказали мне хорошую помощь, и я продолжаю сталкиваться с проблемами.

Для сбора дочерних компаний следующий код работает безупречно, и вывод такой, какой я хотел бы:

with
relations as
(
select orgid as children,org_immediate_parent_orgid as orgid,'Sub' as relation
from oa.organizations 
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

То же самое для AFF:

with
relations as
(
select affiliated_orgid as children, orgid as orgid,'Aff' as relation
from oa.org_affiliations    
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

, но не может иметь "объединение всех"?

with
relations as
(
select orgid as children,org_immediate_parent_orgid as orgid,'Sub' as relation
from oa.organizations

UNION ALL

select affiliated_orgid as children, orgid as orgid,'Aff' as relation
from oa.org_affiliations    
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

В sql developer я пошел и проверил "объясните план и стоимость каждого прыжка с 7 до 400k,просто добавив "union all". Любой обходной путь? Является ли проблема внутри CTE, в union alL?

Решение Боба Джарвиса не будет работать в тех случаях, когда у меня есть comp-sub-sub-aff-aff, или он находитвсе дочерние компании или все филиалы

Ответы [ 3 ]

2 голосов
/ 06 августа 2011

Переход от комментария к реальному ответу и предоставление того, что, я считаю, вам нужно.

Пара вещей ... одна второстепенная ... Я полагаю, у вас есть метки вашего первого соединения по результатам возврата в обратном направлении. Кроме того, я не понимаю, как вы получаете последние две строки в вашем конечном выводе. 4 является родителем 5 лет, а не ребенком, так почему он появляется? А если его там нет, последней строки тоже не будет.

Если я правильно читаю, вы можете использовать что-то вроде:

with
relations as
(
    select
        orgid,
        org_immediate_parent_orgid parent_id,
        'Sub' relation
    from
        organizations
    union all
    select
        orgid,
        null parent_id,
        'Aff' relation
    from
        org_affiliations
    where
        orgid not in (
            select affiliated_orgid
            from org_affiliations
        )
    union all
    select
        affiliated_orgid orgid,
        orgid parent_id,
        'Aff' relation
    from
        org_affiliations
)
select distinct relation, level, parent_id, orgid
from relations
where parent_id is not null
start with orgid = 2
connect by
    nocycle prior orgid = parent_id
order by 2,3,4

Что дает следующий вывод:

RELATION|LEVEL|PARENT_ID|ORGID
Sub     |1    |2        |2
Sub     |2    |2        |1
Aff     |2    |2        |3
Aff     |2    |2        |5
Sub     |3    |1        |3
Aff     |3    |1        |5

Самым большим является то, что 2 таблицы были созданы напротив друг друга (организации имели ссылку на родителя, а филиалы - на ребенка). Поэтому я делаю их в том же формате в предложении WITH, а затем использую соединение by в объединенном наборе.

Кроме того, по какой-то причине Oracle предоставляет первому циклу другой уровень, чем другие, поскольку он является собственной ссылкой. Я предполагаю, что если это проблема, вы можете добавить некоторую пользовательскую логику для этого случая.

1 голос
/ 05 августа 2011

Вот начало:

select 'SUB -> SUB' AS TYPE,
       m.orgid AS ORGID,
       m.org_immediate_parent_orgid AS PARENT_OR_AFF
  from organizations m
  where m.org_immediate_parent_orgid is not NULL
  start with m.orgid in (2)
  connect by nocycle prior m.orgid = m.org_immediate_parent_orgid
UNION ALL
select 'AFF -> AFF' AS TYPE,
       aff.orgid AS ORGID,
       aff.affiliated_orgid AS PARENT_OR_AFF
  from org_affiliations aff
  where aff.affiliated_orgid is not NULL
  start with aff.orgid IN (2)
  connect by nocycle prior aff.affiliated_orgid = aff.orgid;

Если вы добавите подзапросы, чтобы получить оставшиеся отношения, у вас все получится.

Делись и наслаждайся.

0 голосов
/ 15 августа 2011

непроверенная. Создайте представление, чтобы сначала упростить извлечение данных из двух таблиц.

create view related(orgid, relatedid) as 
    select orgid, org_immediate_parent_orgid as relatedid from organizations
    union distinct
    select orgid, affiliated_orgid as relatedid from affiliated;

Теперь мы можем использовать это, чтобы итеративно находить все интересные оргиды.

with recursive related_recursive(orgid, relatedid) as (
    select orgid, relatedid from related where relatedid = 2
    union
    select r.origid, rr.relatedid from related_recursive rr, related r
        where rr.orig = r.relatedid
) 
select orgid from related_recursive;

В этом случае вы могли бы даже удалить столбец relatedid related_recursive, но это полезно и необходимо, если вы хотите удалить или изменить деталь where и выбрать * из related_recursive.

Просто помните, что CTE полностью оцениваются перед основным запросом, поэтому это может привести к потере многих страниц. перед возможной фильтрацией в основном запросе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...