2016-08-30 22 views
2

子ノードの親パスを取得するために、階層的なクエリを書く際に助けが必要です。関数sys_connect_by_pathを使用しようとしていますが、親タイトルを持つ関数の結果がcolumn(4000 chars)の最大文字数制限を超えているため、これを行うことができません。だから私はカスタムコレクションや、私が思いつくのが難しいと思っているclobにパスを保持する必要があります。oracleの子ノードのツリー階層を取得する方法は?

例:

contentid  -   parentid 
0   -    null 
1    -    0 
2    -    1 
3   -    2 
4   -    2 
5   -    6 
6   -    3 
7   -    6 

期待される結果:

contentid  -  Expected result set 
0   -    null 
1    -    0 
2   -    1,0 
3   -    2,1,0 
4   -    2,1,0 
5   -    6,3,2,1,0 
6   -    3,2,1,0 
7   -    6,3,2,1,0 

SELECT CHILD_ID, 
     PATH 
FROM (SELECT sys_connect_by_path(CHILD_TITLE, '|') PATH 
      , connect_by_root(PARENT_ID) ROOT_ID, CHILD_ID 
     FROM table 
    CONNECT BY PRIOR CHILD_ID = PARENT_ID 
     ORDER BY CHILD_ID) 
WHERE ROOT_ID IS NULL; 

に子ノードの親のパスを取得するためのクエリ私はCLOB /カスタムでそれを必要とします4000文字以上を保持できるコレクションです。

+0

だけで明確にします。あなたの問題は予期された結果ではなく、むしろ4kの制限がありますか? –

+0

はい、私の問題は4kの制限です。私は先に接続してパスを取得することができます。しかし、結果は4k限界を超えると予想されます。 – ujwal

+0

メインテーブルが頻繁に変更されることが予想されるため、私は気にしないclobに設定された結果に一時テーブルを作成するバックアップ方法があります。中間ノードがある場合はすべての子ノードを注意する必要があります。除去された。 – ujwal

答えて

0

11gR2以上であれば、connect by階層構文の代わりにrecursive subquery factoringを使用できます。

あなたのテーブルを持つt呼び出された場合:あなたが行うことができます

CHILD_ID PARENT_ID CHILD_T 
---------- ---------- ------- 
     0   root 
     1   0 first 
     2   1 second 
     3   2 third 
     4   2 fourth 
     5   6 fifth 
     6   3 sixth 
     7   6 seventh 

with r (child_id, child_title, id_path, title_path) as (
    select child_id, child_title, to_clob(null), to_clob(null) 
    from t 
    where parent_id is null 
    union all 
    select t.child_id, t.child_title, 
    t.parent_id ||','|| r.id_path, r.child_title ||'|'|| r.title_path 
    from r 
    join t on t.parent_id = r.child_id 
) 
select child_id, id_path, title_path 
from r 
order by child_id; 

    CHILD_ID ID_PATH    TITLE_PATH 
---------- -------------------- ---------------------------------------- 
     0 
     1 0,     root| 
     2 1,0,     first|root| 
     3 2,1,0,    second|first|root| 
     4 2,1,0,    second|first|root| 
     5 6,3,2,1,0,   sixth|third|second|first|root| 
     6 3,2,1,0,    third|second|first|root| 
     7 6,3,2,1,0,   sixth|third|second|first|root| 

アンカー部材は、CLOBのにパスを回します。再帰メンバは各タイトルをCLOBに追加し、CLOBをそのデータ型として保持します。

、彼らが表示されることはありませんので、あなたは少し末尾のコンマ/バーを切り落とす、またはクエリを変更することができます。

with r (parent_id, child_id, child_title, id_path, title_path) as (
    select parent_id, child_id, child_title, to_clob(null), to_clob(null) 
    from t 
    where parent_id is null 
    union all 
    select t.parent_id, t.child_id, t.child_title, 
    t.parent_id || case when r.parent_id is not null then ',' end || r.id_path, 
    r.child_title || case when r.parent_id is not null then '|' end || r.title_path 
    from r 
    join t on t.parent_id = r.child_id 
) 
select child_id, id_path, title_path 
from r 
order by child_id; 

    CHILD_ID ID_PATH    TITLE_PATH 
---------- -------------------- ---------------------------------------- 
     0 
     1 0     root 
     2 1,0     first|root 
     3 2,1,0    second|first|root 
     4 2,1,0    second|first|root 
     5 6,3,2,1,0   sixth|third|second|first|root 
     6 3,2,1,0    third|second|first|root 
     7 6,3,2,1,0   sixth|third|second|first|root 

をあなたのサンプル値はCLOBの必要性を実証し、より多くのデータに追加することはありませんダミーのテーブルに生成された値が4Kを超えることを示しています。

insert into t 
select level + 7, level + 6, 'title' 
from dual 
connect by level <= 2000; 

with r (...) -- as above 
select max(length(id_path)), max(length(title_path)) 
from r; 

MAX(LENGTH(ID_PATH)) MAX(LENGTH(TITLE_PATH)) 
-------------------- ----------------------- 
       8920     12031 
0

SYS_CONNECT_BY_PATHは、以下に示すようほとんどLISTAGGのアプリケーションである:最初に、あなたはCONNECT_BY_ROOTとなど、あなたが必要な行を生成しますをクリックし、集計します。下に示すように、明示的に少しずつ明示的に行うことで、集計に必要なもの、レベルの使用順序などをより詳細に制御することができます。注::Oracleの仕組みとは言えませんLISTAGGSYS_CONNECT_BY_PATHよりもずっと遅れて追加されましたが、論理的にはそれがどのように機能するのかについては、内部で説明しています)。

私はLISTAGG関数と並んで、XMLAGGを使用して別の集計を表示します。これは4,000文字の制限がありません。大きな入力データの場合、LISTAGG行は機能しませんが、XMLAGG行は正常に動作し、CLOBを生成します。がんばろう!

クエリ

with 
    t (child_id, parent_id) as (
     select 0, null from dual union all 
     select 1, 0 from dual union all 
     select 2, 1 from dual union all 
     select 3, 2 from dual union all 
     select 4, 2 from dual union all 
     select 5, 6 from dual union all 
     select 6, 3 from dual union all 
     select 7, 6 from dual 
    ) 
select child_id, 
     listagg(parent_id, ',') within group (order by lvl) as gen_tree_1, 
     rtrim(xmlcast(xmlagg(xmlelement(e, parent_id||',') order by lvl) as clob), ',') 
                  as gen_tree_2 
from (select connect_by_root child_id as child_id, parent_id, level as lvl 
      from t 
      connect by child_id = prior parent_id 
     ) 
group by child_id 
order by child_id 
; 

出力

CHILD_ID GEN_TREE_1   GEN_TREE_2 
---------- -------------------- -------------------- 
     0 
     1 0     0 
     2 1,0     1,0 
     3 2,1,0    2,1,0 
     4 2,1,0    2,1,0 
     5 6,3,2,1,0   6,3,2,1,0 
     6 3,2,1,0    3,2,1,0 
     7 6,3,2,1,0   6,3,2,1,0 

8 rows selected. 
関連する問題