Oracle: Comment interroger une table hiérarchique?


10

Contexte

Il s'agit de la construction de certaines vues que nous utiliserons pour les rapports.

J'ai une table des emplacements, les champs clés étant "emplacement" et "parent" .

La structure que ces deux champs créent, au niveau du niveau, est dans le sens de Nom de l'entreprise -> Nom du campus -> Nom du bâtiment -> Nom de l'étage -> Nom de la pièce. Le nom de l'entreprise reste le même et le nom du campus reste le même dans ce cas.

La structure des emplacements ressemble généralement à ceci:

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

Chaque emplacement renvoie à son emplacement parent, qui est finalement le nom de l'organisation. Actuellement, il n'y a qu'une seule organisation et un seul campus.

Buts

  • J'aimerais pouvoir interroger tous les emplacements situés sous un emplacement donné au niveau "Bâtiment". C'est ainsi que je peux retourner des choses comme le nombre de commandes de travail ont été effectuées pour n'importe quel emplacement dans un bâtiment donné.
  • J'aimerais pouvoir déterminer quel sous-emplacement appartient à quel bâtiment . Essentiellement l'inverse; Je voudrais passer de n'importe quel niveau en dessous du niveau du bâtiment et remonter jusqu'à ce qu'est le bâtiment.
  • Je voudrais que ce soit en vue . Cela signifie que j'aimerais avoir un tableau qui, pour chaque élément du niveau "bâtiment", répertorie le bâtiment dans la colonne de gauche et tous les emplacements possibles SOUS ce bâtiment dans la colonne de droite. De cette façon, j'aurais une liste que je pourrais interroger à tout moment pour trouver quels emplacements font partie de quel bâtiment.

Tentatives et bien faire les choses

J'ai essayé de le faire à travers des vues horriblement construites, des requêtes UNION, etc. - qui ont toutes semblé être une mauvaise idée. Je sais qu'Oracle possède un mécanisme pour cela via "CONNECT BY"; Je ne sais tout simplement pas comment l'utiliser.


Comment les nœuds "racine" sont-ils identifiés? Le parent est-il NULLpour eux? Comment identifiez-vous un «niveau de bâtiment»?
a_horse_with_no_name

@a_horse_with_no_name logiquement, je suppose que le niveau "bâtiment" serait n'importe quoi avec un parent qui est le nom du campus, c'est-à-dire n'importe quoi avec un parent de "MAINCAMPUS". La racine de tous les nœuds est "COMPANYNAME", qui est le parent de "MAINCAMPUS", et tous les bâtiments (plus "terrains") ont MAINCAMPUS comme parent.
SeanKilleen

Hou la la! comment avez-vous créé ça !! Google pour "Adjacency Model in SQL", vous serez prêt
srini.venigalla

PS, pour ceux qui étaient intéressés par la façon dont j'ai fait le diagramme, j'ai utilisé un petit site Web astucieux appelé asciiflow.com - je suis un grand fan de telles situations.
SeanKilleen

Réponses:


4

FrusteratedWithFormsDesigner a la bonne direction (+1). Voici ce que je pense que vous recherchez spécifiquement.

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 vue atteint les trois objectifs. Vous pouvez l'interroger pour un bâtiment pour trouver tout ce qu'il contient et vous pouvez l'interroger pour un sous-emplacement pour trouver dans quel bâtiment il se trouve.

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 vous ne voulez pas compter le bâtiment lui-même comme l'un des sous-emplacements, vous pouvez encapsuler la requête existante dans une seule qui élimine les entrées dans lesquelles le bâtiment et la sous-localisation sont identiques.


Leigh, c'était exactement ça. Merci pour l'aide!
SeanKilleen

9

CONNECT BY est la bonne façon de gérer les données naturellement récursives.

Je ne sais pas à quoi ressemble votre table mais peut-être quelque chose comme:

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

Cela devrait obtenir des nœuds sous "BLDG-01".

La START WITHclause est votre cas de base.

Une autre explication (à part celle d'Oracle que je suppose que vous avez déjà lu et avec laquelle vous avez eu des problèmes, elle est probablement très concise):

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

Également:

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

Et:

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


Merci pour la réponse! J'en ai assez pour réaliser que je ne pense pas avoir bien formulé ma question. Ma structure de table a deux colonnes - "emplacement" et "parent". La hiérarchie qu'ils créent est définie par mon graphique ascii. Je voudrais construire une vue qui montre, pour chaque emplacement au niveau "bâtiment", tous les emplacements sous sa branche. Mon objectif est de pouvoir interroger un bâtiment et obtenir tous ses sous-emplacements, ou interroger une sous-localisation et voir à quel bâtiment il appartient, via une vue (donc pas de "bâtiment-x" défini dans la requête). Toute aide serait grandement appréciée!
SeanKilleen

2

Je ne suis pas sûr de bien comprendre votre question, mais peut-être quelque chose comme ça:

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;

Cela vous montrera la hiérarchie pour chaque emplacement

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.