Oracle: ¿Cómo consulto una tabla jerárquica?

10

Antecedentes

Esto es para la construcción de algunas vistas que usaremos para generar informes.

Tengo una tabla de ubicaciones, los campos clave son "ubicación" y "padre" .

La estructura que crean estos dos campos, en términos de nivel, está en la línea del Nombre de la empresa -> Nombre del campus -> Nombre del edificio -> Nombre del piso -> Nombre de la sala. El nombre de la empresa sigue siendo el mismo y el nombre del campus sigue siendo el mismo en este caso.

La estructura de ubicaciones generalmente se ve así:

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

Cada ubicación se vincula a su ubicación principal, que en última instancia es el nombre de la organización. Actualmente, solo hay una organización y un campus.

Metas

  • Me gustaría poder consultar todas las ubicaciones debajo de cualquier ubicación dada en el nivel "Edificio". Esto es para que pueda devolver cosas como cuántos pedidos de trabajo se han realizado para cualquier ubicación dentro de un edificio determinado.
  • Me gustaría poder determinar qué sububicación pertenece a qué edificio . Esencialmente lo contrario; Me gustaría ir desde cualquier nivel por debajo del nivel del edificio y rastrear hasta donde está el edificio.
  • Me gustaría que esto sea en una vista . Eso significa que me gustaría tener una tabla que para cada elemento en el nivel de "edificio", enumere el edificio en la columna de la izquierda y todas las ubicaciones posibles BAJO ese edificio en la columna de la derecha. De esta manera, tendría una lista que podría consultar en cualquier momento para encontrar qué ubicaciones forman parte de cada edificio.

Intentos y hacerlo bien

Intenté hacer esto a través de vistas horriblemente construidas, consultas de UNION, etc., que me han parecido una mala idea. Sé que Oracle posee un mecanismo para esto a través de "CONECTAR POR"; No estoy seguro de cómo usarlo.

SeanKilleen
fuente
¿Cómo se identifican los nodos "raíz"? ¿Es padre NULLpara ellos? ¿Cómo identificas un "nivel de construcción"?
a_horse_with_no_name
@a_horse_with_no_name lógicamente, supongo que el nivel de "edificio" sería cualquier cosa con un padre que sea el nombre del campus, es decir, cualquier cosa con un padre de "MAINCAMPUS". La raíz de todos los nodos es "COMPANYNAME", que es el padre de "MAINCAMPUS", y todos los edificios (más "terrenos") tienen MAINCAMPUS como padre.
SeanKilleen
¡Guauu! ¿Cómo creaste eso? Google para el "Modelo de adyacencia en SQL" estará listo
srini.venigalla
PD: para aquellos que estaban interesados ​​en cómo hice el diagrama, utilicé un ingenioso sitio web llamado asciiflow.com . Soy un gran admirador de situaciones como esa.
SeanKilleen

Respuestas:

4

FrusteratedWithFormsDesigner tiene la dirección correcta (+1). Esto es lo que creo que estás buscando específicamente.

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 logra los tres objetivos. Puede consultar un edificio para encontrar todo lo que contiene y puede consultar una sububicación para encontrar en qué edificio se encuentra.

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

Si no desea contar el edificio en sí como una de las ubicaciones secundarias, puede ajustar la consulta existente en una que elimine las entradas en las que el edificio y la sububicación son iguales.

Leigh Riffel
fuente
Leigh, esto era exactamente eso. ¡Gracias por la ayuda!
SeanKilleen
9

CONNECT BY es la forma correcta de manejar datos que son naturalmente recursivos.

No sé cómo se ve tu mesa, pero tal vez algo así como:

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

Esto debería obtener nodos en "BLDG-01".

La START WITHcláusula es su caso base.

Otra explicación (aparte de la de Oracle, que supongo que ya has leído y con la que has tenido problemas, probablemente sea muy breve):

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

También:

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

Y:

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

FrustratedWithFormsDesigner
fuente
¡Gracias por la respuesta! Lo entiendo lo suficiente como para darme cuenta de que no creo haber formulado bien mi pregunta. La estructura de mi tabla tiene dos columnas: "ubicación" y "padre". La jerarquía que estos crean está definida por mi gráfico ascii. Me gustaría construir una vista que muestre, para cada ubicación en el nivel de "edificio", todas las ubicaciones debajo de su rama. Mi objetivo es poder consultar un edificio y obtener todas sus sububicaciones, o consultar una sububicación y ver a qué edificio pertenece, a través de una vista (por lo que no hay una "construcción-x" definida en la consulta). Cualquier ayuda sería muy apreciada!
SeanKilleen
2

No estoy seguro de entender tu pregunta por completo, pero tal vez algo como esto:

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;

Esto le mostrará la jerarquía de cada ubicación.

un caballo sin nombre
fuente