2016-10-10 12 views
1

自己参照テーブル - HIERARCHY(id, name, parent_id)があります。 この階層のどのノードでもすべての階層を取得する必要があります。例えば、我々は持っている木、どこh1h2は根である:任意のノードでツリーを取得する方法(SQL)

-(h1) 
    | |_(h1_1) 
    | | |_(h1_1_2) 
    | |_(h1_2) 
    | |_(h1_2_1) 
-(h2) 
    | |_(h2_1) 
    | |_(h2_2) 
    |  

は私が必要なもの、それは例えばこのツリーの任意のノードでルートh1ですべてのツリー例えばを取得しますh1_2

 -(h1) 
     |_(h1_1) 
get  | |_(h1_1_2) by h1_2 or h1_2_1, etc 
     |_(h1_2) 
      |_(h1_2_1) 

で私は、クエリを書いた:

WITH RECURSIVE hierarchy_with_parents(id) AS (
    SELECT l.id, l.name, l.parent_id FROM hierarchy AS l WHERE l.id = <any_row_id> 
    UNION ALL 
    SELECT lc.id, lc.name, lc.parent_id FROM hierarchy lc, hierarchy_with_parents lwp WHERE lc.id = lwp.parent_id 
), hierarchy_with_children(id) AS (
    SELECT l.id, l.name, l.parent_id FROM hierarchy AS l WHERE l.id 
    IN (-- sub-query for getting parent id 
    SELECT 
    lwp.id 
    FROM hierarchy_with_parents AS lwp 
    WHERE lwp.parent_id IS NULL 
) 
    UNION ALL 
    SELECT lc.id, lc.name, lc.parent_id FROM hierarchy lc, hierarchy_with_children lwc WHERE lc.parent_id = lwc.id 
) 
SELECT * FROM hierarchy_with_children 

hierarchy_with_parentsから
hierarchy_with_children、親(包括的)に子からサブツリーを返す - すべてのツリーを返します。

それはすべてうまくいくようですが、私はDB専門家ではないので、私のクエリに関する制限やコメントを知りたいのです。 PostgreSQLとOracle 11gの他のソリューションも歓迎します。

ありがとうございました。

+0

http://stackoverflow.com/questions/32096103/selecting-n-rows-in-sql-server – Esty

+1

@TanjimRahman参照:その質問は、SQL Serverについてです、これらの制限はしないでくださいPostgresまたはOracleに適用 –

+1

OK、一部の不適切なユーザは、これをDBA SEに属するとマークしました。なぜ私は不思議です。アプリケーションが自分のDBを管理しているとしても(それは非常にうまくいないかもしれませんが)、問題はそれを解決するための特定のSQLコードです.DBの管理に関するものではありません。 – mathguy

答えて

1

:input_nodeが指定されている場合、最初にそのノードを含むサブツリーのルートを見つけます。これは、ファクタリングされたサブクエリのfind_rootで行われます。次に、そのルートにリンクしているすべての行を単純に収集します。 :input_nodeが既にルートだった場合は、外部クエリでNVL()コールが必要です。その場合、find_rootは行を返しません。スカラー・サブクエリーとして使用される場合、それはnull(少なくともOracleでは)として扱われるため、NVL()を使用して修正できます。再帰の制限のために

with 
    hierarchy as (
     select 2 as child, 1 as parent from dual union all 
     select 3, 2 from dual union all 
     select 4, 1 from dual union all 
     select 5, 4 from dual union all 
     select 7, 6 from dual union all 
     select 8, 7 from dual union all 
     select 9, 6 from dual 
    ), 
    find_root as (
     select parent as rt 
     from hierarchy 
     where connect_by_isleaf = 1  
     start with child = :input_node 
     connect by child = prior parent 
    ) 
select child, parent 
from hierarchy 
start with parent = nvl((select rt from find_root), :input_node) 
connect by parent = prior child; 
関連する問題