Oracle: Como faço para consultar uma tabela hierárquica?

10

fundo

Isso é para a construção de algumas visualizações que usaremos para gerar relatórios.

Eu tenho uma tabela de locais, os campos principais sendo "local" e "pai" .

A estrutura que esses dois campos criam, em nível de nível, segue as linhas de Nome da Empresa -> Nome do Campus -> Nome do Edifício -> Nome do Piso -> Nome da Sala. O nome da empresa permanece o mesmo e o nome do campus permanece o mesmo neste caso.

A estrutura dos locais geralmente se parece com isso:

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

Todo local é vinculado ao local principal, que é o nome da organização. Atualmente, existe apenas uma organização e um campus.

Metas

  • Eu gostaria de poder consultar todos os locais abaixo de qualquer local no nível "Edifício". Isso é para que eu possa retornar coisas como quantas ordens de trabalho foram executadas para qualquer local dentro de um determinado edifício.
  • Eu gostaria de poder determinar qual sub-localização pertence a qual edifício . Essencialmente o contrário; Eu gostaria de ir de qualquer nível abaixo do nível do edifício e rastrear até o que é o edifício.
  • Eu gostaria que isso fosse visto . Isso significa que eu gostaria de ter uma tabela que, para cada item no nível "edifício", liste o edifício na coluna da esquerda e todos os locais possíveis SOB esse edifício na coluna da direita. Dessa forma, eu teria uma lista que eu poderia consultar a qualquer momento para descobrir quais locais fazem parte de qual edifício.

Tentativas e fazer certo

Tentei fazer isso através de visões horrivelmente construídas, consultas UNION etc. - que pareciam uma péssima idéia. Eu sei que a Oracle possui um mecanismo para isso através de "CONNECT BY"; Só não tenho certeza de como usá-lo.

SeanKilleen
fonte
Como os nós "raiz" são identificados? Pai é NULLpara eles? Como você identifica um "nível de construção"?
a_horse_with_no_name
@a_horse_with_no_name logicamente, suponho que o nível de "edifício" seja qualquer coisa com um pai que seja o nome do campus, ou seja, qualquer coisa com um pai de "MAINCAMPUS". A raiz de todos os nós é "COMPANYNAME", que é o pai de "MAINCAMPUS", e todos os edifícios (mais "terrenos") têm MAINCAMPUS como pai.
21413 SeanKilleen
Uau! como você criou isso !! Google por "Modelo de Adjacência em SQL" você vai estar tudo pronto
srini.venigalla
PS: para aqueles que estavam interessados ​​em como eu fiz o diagrama, usei um site bacana chamado asciiflow.com - sou um grande fã de situações como essa.
SeanKilleen

Respostas:

4

FrusteratedWithFormsDesigner tem a direção certa (+1). Aqui está o que eu acho que você está procurando especificamente.

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              

A visão realiza todos os três objetivos. Você pode consultá-lo em busca de um edifício para encontrar tudo o que ele contém e em um sub-local para encontrar em qual edifício ele está.

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 você não quiser contar o próprio edifício como um dos sub-locais, poderá agrupar a consulta existente em um deles para eliminar as entradas nas quais o edifício e a sublocação são iguais.

Leigh Riffel
fonte
Leigh, era exatamente isso. Obrigado pela ajuda!
58530 SeanKilleen
9

CONNECT BY é a maneira correta de lidar com dados naturalmente recursivos.

Não sei como é a sua mesa, mas talvez algo como:

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

Isso deve obter nós em "BLDG-01".

A START WITHcláusula é seu caso base.

Outra explicação (além da Oracle, que suponho que você já leu e teve problemas, provavelmente é muito concisa):

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

Além disso:

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

E:

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

FrustratedWithFormsDesigner
fonte
Obrigado pela resposta! Estou entendendo o suficiente para perceber que não acho que tenha formulado bem minha pergunta. Minha estrutura de tabela possui duas colunas - "local" e "pai". A hierarquia que eles criam é definida pelo meu gráfico ascii. Gostaria de construir uma exibição que mostre, para cada local no nível "edifício", todos os locais abaixo de sua ramificação. Meu objetivo é ser capaz de consultar um edifício e obter todos os seus sub-locais, ou consultar uma sublocação e ver a qual edifício pertence, através de uma exibição (para que não haja um "edifício x" definido na consulta). Qualquer ajuda seria muito apreciada!
214123 Sean12
2

Não sei se entendi completamente sua pergunta, mas talvez algo assim:

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;

Isso mostrará a hierarquia para cada local

um cavalo sem nome
fonte