Oracle: как запросить иерархическую таблицу?

10

Задний план

Это для построения некоторых представлений, которые мы будем использовать для отчетов.

У меня есть таблица местоположений, ключевые поля которых "местоположение" и "родитель" .

Структура, которую создают эти два поля, по уровням, соответствует названиям компании -> название кампуса -> название здания -> название этажа -> название комнаты. Название компании остается прежним, а название Campus в этом случае остается прежним.

Структура локаций обычно выглядит так:

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

Каждое местоположение ссылается на свое родительское местоположение, которое в конечном итоге является названием организации. В настоящее время существует только одна организация и один кампус.

цели

  • Я хотел бы иметь возможность запрашивать все местоположения ниже любого данного местоположения на уровне "здания". Это так, что я могу вернуть такие вещи, как, сколько рабочих заказов было выполнено для любого места в данном здании.
  • Я хотел бы иметь возможность определить, какое подразделение принадлежит какому зданию . По сути наоборот; Я хотел бы перейти с любого уровня ниже уровня здания и проследить, что это за здание.
  • Я хотел бы, чтобы это было в поле зрения . Это означает, что я хотел бы иметь таблицу, в которой для каждого элемента на уровне «здания» перечислены здания в левом столбце и все возможные местоположения ниже этого здания в правом столбце. Таким образом, у меня был бы список, к которому я мог бы обратиться в любое время, чтобы найти, какие места являются частью какого здания.

Попытки и правильные поступки

Я пытался сделать это с помощью ужасно сконструированных представлений, запросов UNION и т. Д., Которые кажутся плохой идеей. Я знаю, что Oracle обладает механизмом для этого через «CONNECT BY»; Я просто не уверен, как это использовать.

SeanKilleen
источник
Как идентифицируются «корневые» узлы? Родитель NULLдля них? Как вы определяете «уровень здания»?
a_horse_with_no_name
@a_horse_with_no_name логически, я предполагаю, что уровень "здания" будет любым с родителем, который является названием кампуса, то есть с родителем "MAINCAMPUS". Корнем всех узлов является «COMPANYNAME», который является родителем «MAINCAMPUS», а все здания (плюс «основания») имеют MAINCAMPUS в качестве родителя.
SeanKilleen
Вот это да! как ты это создал !! Google для "Модель смежности в SQL" у вас все будет готово
srini.venigalla
PS, для тех, кому было интересно, как я сделал диаграмму, я использовал изящный маленький веб-сайт asciiflow.com - я большой поклонник подобных ситуаций.
SeanKilleen

Ответы:

4

FrusteratedWithFormsDesigner имеет правильное направление (+1). Вот то, что я думаю, вы ищете специально.

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              

Представление выполняет все три цели. Вы можете запросить его для здания, чтобы найти все, что оно содержит, и вы можете запросить его для подобласти, чтобы найти, в каком здании оно находится.

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

Если вы не хотите считать само здание как одно из подразделов, вы можете заключить существующий запрос в один, удаляя записи, в которых здание и подраздел являются одинаковыми.

Ли Риффель
источник
Ли, это было именно так. Спасибо вам за помощь!
SeanKilleen
9

CONNECT BY это правильный способ обработки данных, которые являются естественно рекурсивными.

Я не знаю, как выглядит ваш стол, но может быть что-то вроде:

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

Это должно получить узлы под "BLDG-01".

START WITHРаздел Ваш базовый случай.

Другое объяснение (кроме Oracle, которое, как я полагаю, вы уже прочитали и с которым возникли проблемы, возможно, очень кратко):

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

Также:

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

И:

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

FrustratedWithFormsDesigner
источник
Спасибо за ответ! Я получаю это достаточно, чтобы понять, что не думаю, что хорошо сформулировал свой вопрос. В моей структуре таблицы есть два столбца - «местоположение» и «родитель». Иерархия, которую они создают, определяется моей диаграммой ASCII. Я хотел бы построить представление, которое показывает для каждого местоположения на уровне "здания" все местоположения под его ветвью. Моя цель состоит в том, чтобы иметь возможность запрашивать здание и получать все его местоположения, или запрашивать подраздел, и видеть, к какому зданию оно принадлежит, через представление (так что в запросе нет четко определенного «building-x»). Любая помощь будет принята с благодарностью!
SeanKilleen
2

Я не уверен, что полностью понимаю ваш вопрос, но может быть что-то вроде этого:

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;

Это покажет вам иерархию для каждого местоположения

a_horse_with_no_name
источник