У меня есть таблица с строк описания дерева, столбцы: (колонка 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
мне нужно заполнить table_tree
записей из items_tree
таблица. Для этого я использую пакет, в нем определены item_rec_type
, tree_table_type
, table_tree
и две процедуры: print_tree
, которая извлекает элементы дерева ROOT
, запускает процесс и печатает дерево с table_tree
. Вторая процедура get_items_by_parent_recursively
- это рекурсивная процедура, которая извлекает все элементы или родительский элемент, например. по телефону get_items_by_parent_recursively('Abraham')
добавит Исаак и Ishmael до table_tree
.
Курсор объявляется в теле пакета:
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;
Код в get_items_by_parent_recursively
, который извлекает элементы для родителя:
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;
Выполнение этой процедуры я получаю исключение: CURSOR_ALREADY_OPEN
.
Я искал ответ, но никто не приблизился к тому, что мне нужно. Буду признателен за любые идеи.
Я попытаюсь сделать курсор get_children_cur
частью рекурсивной процедуры.
Я думаю, что курсор должен быть объявлен внутри тела процедуры, я не вижу объявления. Вы пробовали это? – vmachan
Так же, как и не указывая курсор, ваш код недействителен различными способами (опечатка 'vharchar', включая размер в формальном определении параметра, несогласованные имена и тип данных - даже название процедуры слишком велико). [Полный и рабочий пример] (http://stackoverflow.com/help/mcve) был бы намного более полезен, как и ожидаемый результат. Вам действительно нужен PL/SQL для этого - кажется, что-то вы можете сделать с иерархическим запросом или рекурсивным CTE, но зависит от того, какой результат вы хотите ... –
Указанный вами курсор также недействителен. Имена столбцов не соответствуют определению вашей таблицы, вы снова ограничили размер параметра и откуда «p_child»? И где 'p_parent', исходящий из вызова open-cursor в процедуре, - это должно быть' l; _parent' или, более вероятно, 'l_child'? Я могу догадаться, что вы пытаетесь сделать и написать что-то для этого; но это возвращается к тому, почему вы используете PL/SQL вообще ... –