2017-02-08 3 views
0

でレコード表を移入するために、私は木を記述した行を持つテーブルがあるが、次のとおりです。 (列child_numが固有で主キーとして使用)、列はどのように2つのレベルの列親子

TABLE items_tree (
     child_num  number, 
     parent_ref  varchar2(10), 
     child_ref  varchar2(10) 
); 

TYPE item_rec_type IS RECORD (
     item_id   NUMBER, 
     spaces_number NUMBER, 
     parent_ref  VARCHAR2(10), 
     child_ref  VARCHAR2(10) 
); 

TYPE tree_table_type IS TABLE OF item_rec_type%ROWTYPE 
    INDEX BY BINARY_INTEGER; 

table_tree  tree_table_type; -- table of all items 
テーブル items_treeため

例データ(child_numの値は関係ありません):

parent_ref child_ref 
--------------------------- 
null   Abraham 
Abraham  Isaac 
Abraham  Ishmael 
Isaac  Jakob 
Jakob  Yehuda 
Jakob  Josef 
Jakob  Benjamin 
Yehuda  David 
Josef  Efraim 
Josef  Menashe 
David  Solomon 
Solomon  Isaiah 
Isaiah  Jeremiah 

私はを移入する必要がありますrecords from items_treeテーブル。これを行うには、item_rec_type,tree_table_type,table_treeというパッケージが定義されており、2つの手順:は、ROOTのツリーの項目を取得し、処理を開始し、table_treeからツリーを印刷します。第2の手順get_items_by_parent_recursivelyは、すべてのアイテムまたは親アイテムを検索する再帰的プロシージャである。 get_items_by_parent_recursively('Abraham')を呼び出すと、IsaacIshmaeltable_treeが追加されます。

カーソルは、パッケージ本体で宣言されています。親のためのアイテムを取得しget_items_by_parent_recursively

CURSOR get_children_cur(c_parent in varchar2(10)) 
IS 
    SELECT  parent_ref, child_ref 
    FROM  items_tree 
    WHERE parent_ref = c_parent 
    ORDER BY 1, 2; 

コード:CURSOR_ALREADY_OPEN

このプロシージャを実行
procedure get_items_by_parent_recursively(p_parent in VARCHAR2(10), p_spaces_number in NUMBER) 
AS 
    l_spaces_number NUMBER := 0; 
    l_child   VHARCHAR2(10); 
    l_parent   VHARCHAR2(10); 
BEGIN 
    l_spaces_number := p_spaces_number + 3; 

    OPEN get_children_cur(p_parent); 
    LOOP 
    FETCH get_children_cur INTO l_parent, l_child; 
    EXIT WHEN get_children_cur%NOTFOUND; 

    IF (l_child is not null) THEN 
     v_row_number := v_row_number + 1; 
     tree_table(v_row_number).row_num  := v_row_number; 
     tree_table(v_row_number).spaces_number := l_spaces_number; 
     tree_table(v_row_number).parent_ref := l_parent; 
     tree_table(v_row_number).child_ref  := l_child; 

     -- Calling procedure recursively 
     get_items_by_parent_recursively(l_child, l_spaces_number); 
    END IF; 

    END LOOP; 
    CLOSE get_children_cur; 

EXCEPTION 
    WHEN CURSOR_ALREADY_OPEN THEN 
    DBMS_OUTPUT.put_line(' Exception -- CURSOR_ALREADY_OPEN'); 
    WHEN INVALID_CURSOR THEN 
    DBMS_OUTPUT.put_line(' Exception -- INVALID_CURSOR'); 
    WHEN INVALID_NUMBER THEN 
    DBMS_OUTPUT.put_line(' Exception -- INVALID_NUMBER'); 
    WHEN NO_DATA_FOUND THEN 
    DBMS_OUTPUT.put_line(' Exception -- NO_DATA_FOUND'); 
    WHEN PROGRAM_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- PROGRAM_ERROR'); 
    WHEN ROWTYPE_MISMATCH THEN 
    DBMS_OUTPUT.put_line(' Exception -- ROWTYPE_MISMATCH'); 
    WHEN STORAGE_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- STORAGE_ERROR'); 
    WHEN TOO_MANY_ROWS THEN 
    DBMS_OUTPUT.put_line(' Exception -- TOO_MANY_ROWS'); 
    WHEN VALUE_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- VALUE_ERROR'); 

END get_items_by_parent_recursively; 

私は例外を取得しています。

私は返信を検索しましたが、私が必要とするものに近いものはありませんでした。私はどんな考えにも感謝します。

私はカーソルを再帰的手順の一部にすることを試みます。get_children_cur

+1

私はカーソルが手続き本体内で宣言される必要があると思いますが、宣言は表示されません。あなたはそれを試しましたか? – vmachan

+0

カーソルを表示しないだけでなく、あなたのコードはさまざまな方法で無効です(仮パラメータ定義のサイズ、一貫性のない名前とデータ型、プロシージャ名が長すぎても、 'vharchar'のスペルミス)。 [完全で実用的な例](http://stackoverflow.com/help/mcve)は、期待される出力と同様に、はるかに役立ちます。これにはPL/SQLが本当に必要ですか?階層的な問合せや再帰的なCTEで実行できるもののようですが、どの出力を必要とするかによって異なります... –

+0

表示されたカーソルも無効です。カラム名があなたのテーブル定義と一致せず、パラメータサイズを再び制限しました。どこから 'p_child'が来るのですか?そして、プロシージャのオープンカーソル呼び出しから来る 'p_parent'は' l; _parent'、あるいは 'l_child'でしょうか?私はあなたが何をしようとしているのか、それについて何かを書くことを推測することができます。しかし、PL/SQLをまったく使用していないのはなぜですか? –

答えて

1

@vmachanによると、カーソル定義をプロシージャに移動する必要があります。プロシージャの外側ではあるが、パッケージ仕様または本体にはそのセッションがありますが、セッションのグローバルなインスタンスが1つあります。プロシージャを呼び出すたびに同じカーソルが開こうとします。 print_treeからの最初の呼び出しが成功し、テーブルには 'Abraham'が入力されます。再帰呼び出しは再オープンを試み、CURSOR_ALREADY_OPEN例外を取得して停止します。

プロシージャにカーソルを移動すると、各コール/反復にはそれぞれ独自のコピーがあります。ネーミングおよび他のさまざまな問題のクリーンアップ、これは、動作します:

procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER) 
AS 
    l_spaces_number NUMBER := 0; 
    l_child   VARCHAR2(10); 
    l_parent   VARCHAR2(10); 

    CURSOR get_children_cur(p_parent in varchar2) IS 
    SELECT parent_item, child_item 
    from items_tree 
    where parent_item = p_parent 
    or (p_parent is null and parent_item is null); 

BEGIN 
    l_spaces_number := p_spaces_number + 3; 

    OPEN get_children_cur(p_parent); 
    LOOP 
    FETCH get_children_cur INTO l_parent, l_child; 
    EXIT WHEN get_children_cur%NOTFOUND; 

    IF (l_child is not null) THEN 
     v_row_number := v_row_number + 1; 
     table_tree(v_row_number).item_id   := v_row_number; 
     table_tree(v_row_number).spaces_number := l_spaces_number; 
     table_tree(v_row_number).parent_item_ref := l_parent; 
     table_tree(v_row_number).item_ref  := l_child; 

     -- Calling procedure recursively 
     get_items_by_parent(l_child, l_spaces_number); 
    END IF; 

    END LOOP; 
    CLOSE get_children_cur; 

EXCEPTION 
    WHEN CURSOR_ALREADY_OPEN THEN 
    DBMS_OUTPUT.put_line(' Exception -- CURSOR_ALREADY_OPEN'); 
    WHEN INVALID_CURSOR THEN 
    DBMS_OUTPUT.put_line(' Exception -- INVALID_CURSOR'); 
    WHEN INVALID_NUMBER THEN 
    DBMS_OUTPUT.put_line(' Exception -- INVALID_NUMBER'); 
    WHEN NO_DATA_FOUND THEN 
    DBMS_OUTPUT.put_line(' Exception -- NO_DATA_FOUND'); 
    WHEN PROGRAM_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- PROGRAM_ERROR'); 
    WHEN ROWTYPE_MISMATCH THEN 
    DBMS_OUTPUT.put_line(' Exception -- ROWTYPE_MISMATCH'); 
    WHEN STORAGE_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- STORAGE_ERROR'); 
    WHEN TOO_MANY_ROWS THEN 
    DBMS_OUTPUT.put_line(' Exception -- TOO_MANY_ROWS'); 
    WHEN VALUE_ERROR THEN 
    DBMS_OUTPUT.put_line(' Exception -- VALUE_ERROR'); 

END get_items_by_parent; 

あなたが記述内容に基づいてprint_treeを発明:

procedure print_tree is 
begin 
    get_items_by_parent(null, 0); 

    for i in 1..table_tree.count loop 
    dbms_output.put_line(to_char(table_tree(i).item_id, '99999') || ' ' 
     || lpad(' ', table_tree(i).spaces_number, ' ') 
     || table_tree(i).item_ref); 
    end loop; 
end print_tree; 

[email protected]は、カーソルループのためのさまざまで、より簡単に同じ結果を得ることができ、言ったように

1 Abraham 
2  Isaac 
3   Jakob 
4    Yehuda 
5    David 
6     Solomon 
7      Isaiah 
8       Jeremiah 
9    Josef 
10    Efraim 
11    Menashe 
12    Benjamin 
13  Ishmael 

procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER) 
AS 
    l_spaces_number NUMBER := 0; 

    CURSOR get_children_cur(p_parent in varchar2) IS 
    SELECT parent_item, child_item 
    from items_tree 
    where child_item is not null 
    and (parent_item = p_parent 
    or (p_parent is null and parent_item is null)); 

BEGIN 
    l_spaces_number := p_spaces_number + 3; 

    FOR r IN get_children_cur(p_parent) 
    LOOP 
    v_row_number := v_row_number + 1; 
    table_tree(v_row_number).item_id   := v_row_number; 
    table_tree(v_row_number).spaces_number := l_spaces_number; 
    table_tree(v_row_number).parent_item_ref := r.parent_item; 
    table_tree(v_row_number).item_ref  := r.child_item; 

    -- Calling procedure recursively 
    get_items_by_parent(r.child_item, l_spaces_number); 
    END LOOP; 
END get_items_by_parent; 

かさえ:

機能するようになりました、と13件のインデントレコードを生成することを呼び出します

01:もちろん
procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER) 
AS 
BEGIN 
    FOR r IN (
    SELECT parent_item, child_item 
    from items_tree 
    where child_item is not null 
    and (parent_item = p_parent 
     or (p_parent is null and parent_item is null))) 
    LOOP 
    v_row_number := v_row_number + 1; 
    table_tree(v_row_number).item_id   := v_row_number; 
    table_tree(v_row_number).spaces_number := p_spaces_number + 3; 
    table_tree(v_row_number).parent_item_ref := r.parent_item; 
    table_tree(v_row_number).item_ref  := r.child_item; 

    -- Calling procedure recursively 
    get_items_by_parent(r.child_item, p_spaces_number + 3); 
    END LOOP; 
END get_items_by_parent; 

、あなたがすべてでPL/SQLまたはテーブルを使用する必要はありません、あなたは階層的なクエリを使用することができます

が、これはPL/SQLの演習であると思われます。再帰的プロシージャを使用する必要がない場合は、bulk collectを使用して、同様のクエリからテーブルを作成できます。

関連する問題