Oracle: come posso eseguire una query su una tabella gerarchica?


10

sfondo

Questo è per la costruzione di alcune viste che useremo per i rapporti.

Ho una tabella di posizioni, i campi chiave sono "posizione" e "genitore" .

La struttura creata da questi due campi, a livello di livello, è simile a Nome azienda -> Nome campus -> Nome edificio -> Nome piano -> Nome sala. Il nome dell'azienda rimane lo stesso e il nome del campus rimane lo stesso in questo caso.

La struttura delle posizioni in genere si presenta così:

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

Ogni posizione ricollega alla posizione principale, che in definitiva è il nome dell'organizzazione. Attualmente, esiste una sola organizzazione e un campus.

obiettivi

  • Vorrei poter eseguire una query su tutte le posizioni al di sotto di una determinata posizione a livello di "Edificio". Questo è così che posso restituire cose come quanti ordini di lavoro sono stati eseguiti per qualsiasi posizione all'interno di un determinato edificio.
  • Vorrei essere in grado di determinare quale sotto-posizione appartiene a quale edificio . Essenzialmente il contrario; Vorrei andare da qualsiasi livello al di sotto del livello dell'edificio e risalire a quello che è l'edificio.
  • Vorrei che questo fosse in vista . Ciò significa che vorrei avere una tabella che per ogni elemento a livello di "edificio", elenca l'edificio nella colonna di sinistra e tutte le possibili posizioni SOTTO quell'edificio nella colonna di destra. In questo modo avrei un elenco che potrei richiedere in qualsiasi momento per trovare quali posizioni fanno parte di quale edificio.

Tentativi e farlo nel modo giusto

Ho tentato di farlo attraverso viste orribilmente costruite, domande UNION, ecc., Che sono sembrate tutte una cattiva idea. So che Oracle possiede un meccanismo per questo attraverso "CONNECT BY"; Non sono sicuro di come usarlo.


Come vengono identificati i nodi "root"? Il genitore è NULLper loro? Come si identifica un "livello di costruzione"?
a_horse_with_no_name

@a_horse_with_no_name logicamente, suppongo che il livello "building" sarebbe qualcosa con un genitore che è il nome del campus, vale a dire qualsiasi cosa con un genitore di "MAINCAMPUS". La radice di tutti i nodi è "COMPANYNAME", che è il genitore di "MAINCAMPUS", e tutti gli edifici (più i "motivi") hanno MAINCAMPUS come genitore.
SeanKilleen,

Wow! come lo hai creato !! Google per "Modello di adiacenza in SQL" sarai pronto
srini.venigalla

PS, per coloro che erano interessati a come ho realizzato il diagramma, ho usato un piccolo sito web chiamato asciiflow.com - sono un grande fan per situazioni del genere.
SeanKilleen,

Risposte:


4

FrusteratedWithFormsDesigner ha la giusta direzione (+1). Ecco cosa penso che tu stia cercando specificamente.

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              

La vista raggiunge tutti e tre gli obiettivi. Puoi interrogarlo per un edificio per trovare tutto ciò che contiene e puoi interrogarlo per un sotto-percorso per trovare in che edificio si trova.

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

Se non si desidera contare l'edificio stesso come una delle posizioni secondarie, è possibile racchiudere la query esistente in una, eliminando le voci in cui l'edificio e la sublocazione sono uguali.


Leigh, era esattamente così. Grazie per l'aiuto!
SeanKilleen,

9

CONNECT BY è il modo corretto di gestire i dati ricorsivi per natura.

Non so come sia il tuo tavolo ma forse qualcosa del genere:

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

Questo dovrebbe ottenere nodi in "BLDG-01".

La START WITHclausola è il tuo caso base.

Un'altra spiegazione (a parte quella di Oracle che presumo tu abbia già letto e con cui hai avuto problemi, è probabilmente molto concisa):

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

Anche:

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

E:

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


Grazie per la risposta! Lo capisco abbastanza per rendermi conto che non penso di aver formulato bene la mia domanda. La struttura della mia tabella ha due colonne: "location" e "parent". La gerarchia che questi creano è definita dal mio grafico ASCII. Vorrei costruire una vista che mostri, per ogni posizione a livello di "edificio", tutte le posizioni sotto il suo ramo. Il mio obiettivo è quello di essere in grado di interrogare un edificio e ottenere tutte le sue posizioni secondarie, o interrogare una sublocazione e vedere a quale edificio appartiene, attraverso una vista (quindi nessuna "costruzione-x" definita nella query). Qualsiasi aiuto sarebbe molto apprezzato!
SeanKilleen,

2

Non sono sicuro di aver compreso completamente la tua domanda, ma forse qualcosa del genere:

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;

Questo ti mostrerà la gerarchia per ogni posizione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.