Первая из ваших закомментированных строк:
--l_val(n) := r_col_val(l_dum_val); -- ORA-06533: Subscript beyond count
получает эту ошибку, потому что вы не сбрасываете n
в ноль перед вторым l oop. Вам даже не нужна эта переменная-счетчик, вы можете использовать вместо нее l_val.count
(в обоих циклах).
Вторая из ваших закомментированных строк:
--l_val(n) := l_dum_val; --PLS-00382: expression is of wrong type
получает эту ошибку, потому что l_val(n)
указывает на объект, который имеет строковый атрибут; он не указывает прямо на строку. Таким образом, вы можете назначить новый объект через его конструктор; это то, что пыталась сделать первая версия, но это должно быть:
l_val(l_val.count) := r_col_val(l_dum_val);
Как только этот объект существует, вы можете назначить атрибут напрямую с помощью:
l_val(some_index).l_col_val := r_col_val(l_dum_val);
, но вы должны создайте объект, прежде чем вы сможете получить доступ к его атрибутам, и, поскольку у вас есть только конструктор по умолчанию, в этом случае он, вероятно, вряд ли будет вам полезен.
Так же и с этими изменениями (и некоторыми отступами, и немного рефакторинг, чтобы избавиться от else
), теперь это работает:
CREATE OR REPLACE FUNCTION
GET_REF_VAL
(
p_cursor IN SYS_REFCURSOR
)
RETURN t_col_val
IS
l_val t_col_val := t_col_val();
l_col t_col_head := t_col_head();
l_cursor SYS_REFCURSOR := p_cursor;
l_cursor_id INTEGER;
l_dummy INTEGER;
l_col_cnt INTEGER;
l_tab_rec DBMS_SQL.DESC_TAB2;
l_dum_val VARCHAR2(250);
BEGIN
l_cursor_id := DBMS_SQL.TO_CURSOR_NUMBER(l_cursor);
DBMS_SQL.DESCRIBE_COLUMNS2(l_cursor_id, l_col_cnt, l_tab_rec);
/* COLUMN HEADERS */
FOR r IN 1..l_col_cnt
LOOP
l_col.extend;
l_col(l_col.count) := r_col_head(l_tab_rec(r).col_name);
DBMS_SQL.DEFINE_COLUMN(l_cursor_id, r, l_dum_val, 4000);
END LOOP;
/* COLUMN VALUES */
LOOP
IF DBMS_SQL.FETCH_ROWS(l_cursor_id) = 0 THEN
EXIT;
END IF;
FOR i IN 1 .. l_col_cnt
LOOP
l_val.extend;
DBMS_SQL.COLUMN_VALUE(l_cursor_id, i, l_dum_val);
DBMS_OUTPUT.PUT_LINE(l_dum_val);
l_val(l_val.count) := r_col_val(l_dum_val);
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(l_cursor_id);
RETURN l_val;
END;
/
db <> fiddle
Ваш код предполагает, что у вас есть Отдельная функция для получения заголовков, поэтому вы дублируете код. Вместо этого вы могли бы упростить до одной процедуры две переменные:
CREATE OR REPLACE PROCEDURE
GET_REF_HEAD_AND_VAL
(
p_cursor IN OUT SYS_REFCURSOR,
p_col OUT SYS.odcivarchar2list,
p_val OUT SYS.odcivarchar2list
)
IS
l_cursor_id INTEGER;
l_col_cnt INTEGER;
l_tab_rec DBMS_SQL.DESC_TAB3;
l_value VARCHAR2(250 byte);
BEGIN
l_cursor_id := DBMS_SQL.TO_CURSOR_NUMBER(p_cursor);
DBMS_SQL.DESCRIBE_COLUMNS3(l_cursor_id, l_col_cnt, l_tab_rec);
/* COLUMN HEADERS */
p_col := SYS.odcivarchar2list();
FOR r IN 1..l_col_cnt
LOOP
p_col.extend;
p_col(p_col.count) := l_tab_rec(r).col_name;
DBMS_SQL.DEFINE_COLUMN(l_cursor_id, r, l_value, 250);
END LOOP;
/* COLUMN VALUES */
p_val := SYS.odcivarchar2list();
LOOP
IF DBMS_SQL.FETCH_ROWS(l_cursor_id) = 0 THEN
EXIT;
END IF;
FOR i IN 1 .. l_col_cnt
LOOP
p_val.extend;
DBMS_SQL.COLUMN_VALUE(l_cursor_id, i, l_value);
--DBMS_OUTPUT.PUT_LINE(l_dum_val);
p_val(p_val.count) := l_value;
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(l_cursor_id);
END;
/
При этом используется встроенный тип коллекции вместо создания собственных типов объектов / таблиц (хотя вы все равно можете создать свой собственный тип коллекции; для этого не нужно использовать объекты).
db <> fiddle