#oracle #stored-procedures #plsql #sys-refcursor #bulk-collect
#Oracle #хранимые процедуры #plsql #системный рефкурсор #массовый сбор
Вопрос:
В приведенном ниже примере у меня есть SP, который вернет SYS_REFCURSOR в качестве параметра OUT службе Java, и в том же SP он вставит результат SYS_REFCURSOR в другой пример таблицы — temp. Когда я выполняю SP, он выдает ошибку
ORA-01002: ошибка извлечения из последовательности
Я вижу, что данные вставляются, но служба не возвращает никакого РЕФКУРСОРА службе.
create or replace procedure ins_act(l_result OUT sys_refcursor)
as
--Created a RECORD type to hold the result of the SYS_REFCURSOR
TYPE RSLT IS RECORD
(
l_id1 varchar2(32),
l_id2 varchar2(32),
l_id3 varchar2(32),
l_pid varchar2(16),
l_ac varchar2(32),
l_activity_date varchar2(32),
l_file_id varchar2(64)
) ;
--Created associative array to hold the result
Type v_reslt is table of RSLT index by PLS_INETEGER;
--Variable to Record type
var_reslt v_res<
begin
-- Procedure to pull the get records
OPEN l_result FOR
SELECT COL1,COL2,COL3,CoUnt(*).....
-- Bulk fetch
Loop
fetch l_result bulk collect into var_reslt limit 100;
--Bulk Insert
FORALL I INTO 1..var_reslt.count SAVE EXCEPTIONS
insert into temp(id1,
id2,
id3,
platform_id,
activity_code,
update_timestamp,
file_id)
values
(to_char(to_date(var_reslt(i).l_id1,'mm/dd/yyyy'),'mm/dd/yyyy'),
var_reslt(i).l_id2,
var_reslt(i).l_id3,
0,
var_reslt(i).l_ac,
var_reslt(i).l_activity_date,
var_reslt(i).l_file_id);
exit when l_result%notfound;
end loop;
Commit;
close l_resu<
Exception
WHEN OTHERS
THEN
--Bulk Exception handling
FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
DBMS_OUTPUT.put_line (
SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX
|| ‘: ‘
|| SQL%BULK_EXCEPTIONS (indx).ERROR_CODE);
RAISE;
end;
/
Ответ №1:
Несколько проблем с этим кодом.
Во-первых, вы проверяете, нашел ли курсор что-либо после оператора FORALL. Это неправильно, потому что оператор FORALL пытается обработать курсор, даже когда курсор находится %notfound
. Это может быть источником вашего исключения ORA-01002.
Вторая ошибка является незначительной. Проверка наличия курсора %notfound
— это проблема с предложением LIMIT, потому что она будет оцениваться true
, когда курсор вернет любое количество записей, меньшее предела: это будет %notfound
, даже если курсор вернет 99 записей. Это неинтуитивный аспект реализации PL / SQL. В любом случае, лучше проверить количество записей в коллекции.
Вот ваш код, исправленный для этих двух проблем:
create or replace procedure ins_act(l_result OUT sys_refcursor) as
TYPE RSLT IS RECORD (
l_id1 varchar2(32),
l_id2 varchar2(32),
l_id3 varchar2(32),
l_pid varchar2(16),
l_ac varchar2(32),
l_activity_date varchar2(32),
l_file_id varchar2(64)) ;
Type v_reslt is table of RSLT index by PLS_INETEGER;
var_reslt v_res<
begin
OPEN l_result FOR
SELECT COL1,COL2,COL3,CoUnt(*).....
Loop
fetch l_result bulk collect into var_reslt limit 100;
exit when var_reslt.count() = 0;
--Bulk Insert
FORALL I INTO 1..var_reslt.count SAVE EXCEPTIONS
insert into temp(id1,
id2,
id3,
platform_id,
activity_code,
update_timestamp,
file_id)
values
(to_char(to_date(var_reslt(i).l_id1,'mm/dd/yyyy'),'mm/dd/yyyy'),
var_reslt(i).l_id2,
var_reslt(i).l_id3,
0,
var_reslt(i).l_ac,
var_reslt(i).l_activity_date,
var_reslt(i).l_file_id);
end loop;
Commit;
close l_resu<
Exception
WHEN OTHERS
THEN
--Bulk Exception handling
FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
DBMS_OUTPUT.put_line (
SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX
|| ‘: ‘
|| SQL%BULK_EXCEPTIONS (indx).ERROR_CODE);
RAISE;
end;
/
Последняя ошибка является процедурной. Рефкурсор — это одноразовый прием. Вы читаете его в программе, что означает, что он исчерпан, когда вы передаете его обратно на уровень java. Есть несколько способов решить эту проблему, в зависимости от того, чего именно вы пытаетесь достичь. Опубликуйте более подробную информацию о вашей логике.
Комментарии:
1. Мое требование — вернуть sys_refcursor C1 в службу и вставить тот же sys_refcursor C1 в другую таблицу . я попытался внести упомянутое выше изменение, но по-прежнему получаю ошибку извлечения из последовательности
2. Насколько близок ваш фактический код к опубликованному вами коду? Очевидно, вы отредактировали проекцию оператора SELECT: упростили ли вы другие биты, пропустили циклы и т. Д.? Потому что трудно понять, как опубликованный код может выдавать ORA-01002 (то, что я отправляю, может выдать это, было предположением: я не видел ORA-01002, вызванного этим конкретным средством аннулирования курсора).