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.


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, 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


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.