Oracle: Jak wykonać zapytanie do tabeli hierarchicznej?

10

tło

Jest to konstrukcja niektórych widoków, których będziemy używać do raportowania.

Mam tabelę lokalizacji, a kluczowymi polami są „lokalizacja” i „rodzic” .

Struktura, którą te dwa pola tworzą, pod względem poziomu, jest zgodna z nazwą firmy -> nazwa kampusu -> nazwa budynku -> nazwa piętra -> nazwa pokoju. Nazwa firmy pozostaje taka sama, a nazwa kampusu pozostaje taka sama w tym przypadku.

Struktura lokalizacji ogólnie wygląda następująco:

                                 +-----------+
                                 | Org. Name |
                                 +-----+-----+
                                       |
                                 +-----v-----+
           +--------------------+|Campus Name|+---+--+-------------+
           |                     +--+--------+    |                |
           |                        |             |                |
           |                        |             |                |
        +--+-----+           +------+-+        +--+----+       +---+---+
    +--+| BLDG-01|+--+       | BLDG-02|        |BLDG-03|       |Grounds|
    |   +--------+   |       +--------+        +-------+       +-------+
  +-+------+   +-----+--+
  |Floor-01|   |Basement+-------+
  +-+------+   +--------+       |
    |                           |
    |                           |
    | +----------+      +-------+--+
    +-+Room 1-001|      |Room B-002|
      +----------+      +----------+

Każda lokalizacja prowadzi z powrotem do swojej lokalizacji nadrzędnej, która ostatecznie jest nazwą organizacji. Obecnie istnieje tylko jedna organizacja i jeden kampus.

Cele

  • Chciałbym móc sprawdzać wszystkie lokalizacje poniżej dowolnej lokalizacji na poziomie „Budynku”. Dzięki temu mogę zwrócić rzeczy, takie jak liczbę zleceń wykonanych dla dowolnej lokalizacji w danym budynku.
  • Chciałbym być w stanie określić, która podstacja należy do którego budynku . Zasadniczo odwrotnie; Chciałbym przejść z dowolnego poziomu poniżej poziomu budynku i prześledzić z powrotem do tego, czym jest budynek.
  • Chciałbym, żeby to było w zasięgu wzroku . Oznacza to, że chciałbym mieć tabelę, która dla każdego elementu na poziomie „budynku” zawiera listę budynku w lewej kolumnie i wszystkie możliwe lokalizacje POD tym budynkiem w prawej kolumnie. W ten sposób miałbym listę, którą mogłem w dowolnym momencie przeszukać, aby ustalić, które lokalizacje są częścią danego budynku.

Próby i robienie tego dobrze

Próbowałem to zrobić poprzez okropnie skonstruowane widoki, zapytania UNION itp. - które wydawały się złym pomysłem. Wiem, że Oracle posiada do tego mechanizm poprzez „CONNECT BY”; Po prostu nie jestem pewien, jak to wykorzystać.

SeanKilleen
źródło
Jak identyfikowane są węzły „root”? Czy jest NULLdla nich rodzicem ? Jak rozpoznać „poziom budynku”?
a_horse_w_na_nazną
@ logicznie_na_nazwie bez nazwy, przypuszczam, że poziom „budowania” byłby czymkolwiek z rodzicem, który jest nazwą kampusu, tj. czymkolwiek z rodzicem „MAINCAMPUS”. Podstawą wszystkich węzłów jest „COMPANYNAME”, który jest rodzicem „MAINCAMPUS”, a wszystkie budynki (plus „grunty”) mają MAINCAMPUS jako rodzic.
SeanKilleen
łał! jak to stworzyłeś !! Google dla „modelu adjacencji w SQL” wszystko będzie
gotowe
PS, dla tych, którzy byli zainteresowani tym, jak zrobiłem schemat, skorzystałem z fajnej małej witryny o nazwie asciiflow.com - jestem wielkim fanem takich sytuacji.
SeanKilleen

Odpowiedzi:

4

FrusteratedWithFormsDesigner ma właściwy kierunek (+1). Oto, jak myślę, czego konkretnie szukasz.

CREATE OR REPLACE VIEW BuildingSubs AS
   SELECT connect_by_root location "Building", location "SubLocation"
   FROM some_table l
   START WITH l.Location IN 
      (
         SELECT location FROM
         (
         SELECT level MyLevel, location FROM some_table 
         START WITH parent IS NULL 
         CONNECT BY PRIOR location=parent
         )
         WHERE MyLevel=3   
      )
   CONNECT BY PRIOR l.location = l.parent;

select * from BuildingSubs; 

Building             SubLocation        
-------------------- --------------------
BLDG-01              BLDG-01              
BLDG-01              Basement             
BLDG-01              Room B-002           
BLDG-01              Floor-01             
BLDG-01              Room 1-001           
BLDG-02              BLDG-02              
BLDG-03              BLDG-03              
Grounds              Grounds              

Widok osiąga wszystkie trzy cele. Możesz zapytać go o budynek, aby znaleźć wszystko, co zawiera, i możesz zapytać go o pod-lokalizację, aby znaleźć budynek.

drop table some_table;
create table some_table (Location Varchar2(20), Parent Varchar2(20));

insert into some_table values ('Org. Name',NULL);
insert into some_table values ('MAINCAMPUS','Org. Name');
insert into some_table values ('BLDG-01','MAINCAMPUS');
insert into some_table values ('BLDG-02','MAINCAMPUS');
insert into some_table values ('BLDG-03','MAINCAMPUS');
insert into some_table values ('Grounds','MAINCAMPUS');
insert into some_table values ('Floor-01','BLDG-01');
insert into some_table values ('Basement','BLDG-01');
insert into some_table values ('Room B-002','Basement');
insert into some_table values ('Room 1-001','Floor-01');

Jeśli nie chcesz liczyć samego budynku jako jednej z pod-lokalizacji, możesz zawinąć istniejące zapytanie w jedną, eliminując wpisy, w których budynek i sublokacja są takie same.

Leigh Riffel
źródło
Leigh, właśnie o to chodziło. Dziękuję za pomoc!
SeanKilleen,
9

CONNECT BY to właściwy sposób obsługi danych, które są naturalnie rekurencyjne.

Nie wiem, jak wygląda twój stół, ale może coś takiego:

SELECT *
FROM some_table st
START WITH st.location = 'BLDG-01'
CONNECT BY PRIOR st.location = st.parent;

To powinno uzyskać węzły pod „BLDG-01”.

START WITHKlauzula jest baza sprawa.

Kolejne wyjaśnienie (oprócz Oracle, które, jak zakładam, już przeczytałeś i miałeś problem, to prawdopodobnie bardzo zwięzłe):

http://www.adp-gmbh.ch/ora/sql/connect_by.html

Również:

http://psoug.org/reference/connectby.html

I:

http://www.oradev.com/connect_by.jsp

FrustratedWithFormsDesigner
źródło
Dzięki za odpowiedzi! Dostaję wystarczająco dużo, by zdać sobie sprawę, że nie sądzę, by dobrze sformułowałem swoje pytanie. Moja struktura tabeli ma dwie kolumny - „lokalizacja” i „rodzic”. Hierarchia, którą tworzą, jest określona przez mój wykres ascii. Chciałbym zbudować widok, który pokazuje, dla każdej lokalizacji na poziomie „budynku”, wszystkie lokalizacje poniżej jej gałęzi. Moim celem jest możliwość wysłania zapytania do budynku i uzyskania wszystkich jego pod-lokalizacji lub zapytania o sublokację i zobaczenie, do którego budynku należy, poprzez widok (aby w zapytaniu nie było zdefiniowanego „budynku-x”). Każda pomoc byłaby bardzo mile widziana!
SeanKilleen
2

Nie jestem pewien, czy rozumiem całkowicie twoje pytanie, ale może coś takiego:

select location, 
       parent,
       sys_connect_by_path(location, '/') as item_list,
       case level
         when 1 then 'building'
         when 2 then 'floor'
         when 3 then 'room'
       end as item_type
from some_table 
start with parent = 'MAINCAMPUS'
connect by prior location = parent;

Spowoduje to wyświetlenie hierarchii dla każdej lokalizacji

koń bez imienia
źródło