web-dev-qa-db-ja.com

Oracle:階層テーブルを照会するにはどうすればよいですか?

バックグラウンド

これは、レポートに使用するいくつかのビューを作成するためのものです。

場所のテーブルがありますキーフィールドは "場所"と "親"です。

これら2つのフィールドが作成する構造は、レベルごとに、会社名->キャンパス名->建物名->フロア名->部屋名のラインに沿っています。この場合、会社名は変わりませんが、キャンパス名は変わりません。

ロケーションの構造は通常、次のようになります。

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

すべての場所は、親の場所(最終的には組織名)にリンクします。現在、組織とキャンパスは1つだけです。

ゴール

  • 「Building」レベルで任意の場所の下にあるすべての場所をクエリできるようにしたいと思います。これは、特定の建物内の任意の場所に対して実行された作業指示の数などを返すことができるようにするためです。
  • どのサブロケーションがどの建物に属しているかを判別できるようにしたい。基本的には逆です。建物のレベルの下のどのレベルからでも、建物が何であるかをたどります。
  • これをビューに含めたい。つまり、「建物」レベルのすべての項目について、左側の列に建物、右側の列にその建物の下にある可能性のあるすべての場所がリストされている表が必要です。このようにして、どの場所がどの建物の一部であるかを見つけるためにいつでもクエリを実行できるリストを作成します。

試みとそれを正しく行う

私はひどく構築されたビュー、UNIONクエリなどを使用してこれを試みました-これらはすべて悪い考えのように思えました。 Oracleが「CONNECT BY」を介してこのためのメカニズムを持っていることを知っています。どうやって使うのかよくわからない。

10
SeanKilleen

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              

ビューは3つすべての目標を達成します。建物を照会して、そこに含まれるすべてのものを見つけることができます。また、サブロケーションを照会して、それがどの建物にあるかを見つけることができます。

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

建物自体をサブロケーションの1つとして数えたくない場合は、既存のクエリを1つにラップして、建物とサブロケーションが同じエントリを除外できます。

4
Leigh Riffel

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

私はあなたの質問を完全に理解しているとは思いませんが、おそらく次のようなものです:

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;

これにより、各場所の階層が表示されます