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


10

バックグラウンド

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

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

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

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

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

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

ゴール

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

試みとそれを正しく行う

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


「ルート」ノードはどのように識別されますか?NULL彼らの親ですか?「建物レベル」をどのように特定しますか?
a_horse_with_no_name 2012

@a_horse_with_no_name論理的には、「建物」レベルは、キャンパス名である親を持つもの、つまり「MAINCAMPUS」という親を持つものになると思います。すべてのノードのルートは、「MAINCAMPUS」の親である「COMPANYNAME」であり、すべての建物(および「グラウンド」)は、MAINCAMPUSを親として持っています。
SeanKilleen

うわー!どうやってそれを作ったの!「SQLの隣接モデル」のグーグルはすべて設定されます
srini.venigalla

PS、私が図を作成する方法に興味がある人のために、私はasciiflow.comと呼ばれる気の利いた小さなWebサイトを使用しました-私はそのような状況の大ファンです。
SeanKilleen 2015年

回答:


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              

ビューは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つにラップして、建物とサブロケーションが同じエントリを除外できます。


リー、これはまさにそれでした。お手伝いありがとう!
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


ご返信ありがとうございます!私は自分の質問をうまく表現していないと思うほど十分に理解しています。私のテーブル構造には、「場所」と「親」という2つの列があります。これらが作成する階層は、私の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;

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.