2011-08-05 16 views
11

I baza danych Mam 2 następujące informacje dla każdego identyfikatora. Firma, która je kontroluje, oraz firmy, w których mają niewielką kontrolę.SQL Multi Condition CTE Recursion

coś wzdłuż linii, 2 stoliki (pomijając kilka unikalnych identyfikatorów)

organizacji do

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

Relacja orgid -> org_immediate_parent_orgid Oznacza Firma posiada rodzica. Por mi jej odpowiednie tylko org_immediate_parent_orgid -> orgid rodzic z firm ma za zależnej

org_affiliations

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

orgid -> affiliated_orgid jest Spółka posiada Partnerowi

reprezentacja wizualna powinna być coś takiego:

Database representation

Na czerwonych relacjach z organizacji , na niebieskich relacjach org_affiliations.

Jeśli chcesz, aby wszystkie przedsiębiorstwa należące do 2 (lub zależnej syna 2) ma jakiś udział w niej nich

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 

powraca

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

Jeśli Chcesz uzyskać wszystkie firmy były 2 (lub syn związany z 2) ma jakiś udział w niej nich

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 

powraca

orgid | affiliated_orgid 
2  | 3 
2  | 5 

Więc wszystkich możliwych relacji:

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

Znajduję tylko Sub -> Sub (filie podmiotów zależnych), relacje (2 -> 1 i relacje 1 -> 3) oraz Aff -> Aff, relacje (2 -> 3 i relacje 2 -> 5). Również wymaga 2 oddzielnych zapytań.

Jak mogę pobrać wszystkie możliwe relacje w jednym pojedynczym zapytaniu cyklicznym?

Jeśli mijam identyfikator 2 powinno być możliwe następujące zwrot:

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 

W każdym cyklu byłoby sprawdzić kanapki i oddziałów dla każdego identyfikatora. Powtórz dla nowych dzieci.

Masz pomysł, jak do niego podejść?

TL: DR: 2 stoły (spółki zależne \ podmioty stowarzyszone), 2 zapytania. chcę pojedynczego zapytania, skąd w firmie znajduję wszystkie filie i filie oraz wszystkie możliwe kombinacje subskrybentów. Ostateczny wynik oczekiwany pokaż, wystarczy postępować zgodnie z reprezentacji obrazu.

Edytuj: W komentarzu Craig naprawiłem wyjście.

Edit2: Po dobrej pomocy Craiga i Boba Jarvisa nadal napotykam na problemy.

do zbierania zależnych, następujący kod działa flawlessy, a wyjście jest jak chciałbym:

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 

samo dla 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 

ale mogę mieć "zjednoczenie wszystkich"?

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 

W SQL Developer poszedłem i sprawdzić „wyjaśnić plan i koszty z każdego skoku od 7 do 400K, po prostu dodając«zjednoczenie wszystkich». Wszelkie workarround? Czy problem wewnątrz CTE, w unii wszystko?

Bob Jarvis rozwiązanie praca przyzwyczajenie w przypadkach gdzie mam comp-sub-sub-AFF, czy to wyszukuje wszystkie filie firmy lub wszystkich oddziałów

+2

+1 dla pięknego cięcia. jednak zbyt długo ... nie słuchałem :) – Bohemian

+1

Musiałem to jakoś wyjaśnić: D – blueomega

+1

To za długo, abym czytał, rozumiał i odpowiadał! – Kangkan

Odpowiedz

1

Oto początek na to:

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; 

Jeśli dodasz podzapytania, aby uzyskać pozostałe relacje, powinieneś być gotowy.

Udostępnij i ciesz się.

2

Przeniesienie tego z komentarza do faktycznej odpowiedzi i dostarczenie tego, co uważam za potrzebne.

Kilka rzeczy .. jeden jest niewielki .. Wierzę, że masz etykiety pierwszego połączenia przez wyjście powrotne do tyłu. Ponadto nie wiem, jak uzyskać ostatnie dwa wiersze w końcowym wyniku. 4 jest rodzicem 5, a nie dzieckiem, więc dlaczego się pojawia? A jeśli go nie ma, to ostatnia linia nie będzie tak dobra.

Jeśli czytam to poprawnie, można użyć coś takiego:

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 

co daje następujący wynik:

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 

Najważniejszą rzeczą jest to, że 2 stoliki zostały utworzone przeciwieństwo siebie nawzajem (organizacje miały link do rodzica, powiązania miały link do dziecka). Tak więc robię je w tym samym formacie w klauzuli WITH, a następnie używam connect na połączonym zestawie.

Ponadto, z jakiegoś powodu Oracle daje pierwszej pętli inny poziom niż inne, ponieważ jest samoodniesienia. Zakładam, że jeśli jest to problem, możesz wprowadzić niestandardową logikę dla tego przypadku.

+0

Cześć Craig, wymiana etykiet nie jest problematyczna, system, który je te dane nie obchodzi. Ups 4 powinien być zależny od 5, a nie odwrotnie, doskonały połów. Podsumowując, świetna robota, przeszłość przed pójściem spać, ale źle ją testuję i dostarczam więcej informacji zwrotnych. Każda zmiana powinna być teraz łatwa :) – blueomega

+0

Wygląda na to, że wciąż mam problemy, które wyjaśniłem powyżej. część kwerendy z "null parent_id", jeśli rozumiem ją poprawnie, nie potrzebuję identyfikatorów wyjściowych firm, które nie mają żadnych af. – blueomega

0

Bez przetestowania.Utwórz widok, aby uprościć pobieranie danych z 2 tabel.

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; 

Możemy teraz użyć tego do iteracyjnego znajdowania wszystkich interesujących organów.

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; 

Można nawet usunąć relatedid kolumnę related_recursive w tym przypadku, ale warto i konieczne, jeśli chcesz usunąć lub zmienić, gdy część i select * from related_recursive.

Pamiętaj, że CTE są obliczane w pełni przed głównym zapytaniem, więc może to zająć wiele stron przed ostatecznym filtrowaniem w głównym zapytaniu.

+0

Nie widziałem, żebyś używał połączenia przez, co moim zdaniem jest specyficzne dla oracle? Nie powinno być problemu z przekształceniem tego ze standardowego "z rekursywnym", jeśli oracle jeszcze go nie obsługuje. –