Я не уверен, почему SQL Developer дает такую ошибку; кажется, что он недоволен, пытаясь отобразить ограниченный курсор. Однако из этого окна вывода исходит ошибка, а не ваш код.
Если вы запускаете точно такой же тестовый блок вручную, как сценарий из листа SQL, с клиентской переменной, к которой привязывается выходной курсор, вы не получите сообщение об ошибке:
var cur_custid refcursor;
DECLARE
VAR_JOB VARCHAR2(200);
CUR_CUSTID sys_refcursor;
BEGIN
VAR_JOB := 'teach';
SP_TEMP_1(
VAR_JOB => VAR_JOB,
CUR_CUSTID => CUR_CUSTID
);
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('CUR_CUSTID = ' || CUR_CUSTID);
*/
:CUR_CUSTID := CUR_CUSTID; --<-- Cursor
--rollback;
END;
/
Num Rows: 3
PL/SQL procedure successfully completed.
print cur_custid
Но вы тоже ничего не получите. print
показывает результат курсора, но он пустой.
Проблема действительно в том, что вы использовали курсор в своей процедуре; после этого:
LOOP
FETCH cur_custid
INTO custrec;
EXIT WHEN cur_custid%notfound;
---looping happens
END LOOP;
Вы, очевидно, встретили cur_custid%notfound
, что означает, что в курсоре не осталось строк. Нет перемотки, автоматической или ручной; поэтому, когда вызывающая сторона получает контроль над этой переменной out, курсор остается пустым. Или, если вы предпочитаете думать об этом так, указатель курсора по-прежнему указывает на конец данных - не осталось строк для использования. (Опять же, почему ошибки мастера выполнения процедур в этот момент неясны.)
Ваша посылка:
Мне нужно проверить количество сотрудников, и если число больше нуля, я должен использовать тот же оператор выбора. Вместо выполнения одного и того же оператора выбора несколько раз я попытался
... имеет недостатки. Вы можете делать то, что делаете, но, когда вы используете курсор, вам нужно снова его открыть, что все равно повторяет оператор:
IF cur_custid%rowcount = 0
THEN
dbms_output.put_line('Zero Rows Condition Met. Opening Cursor.');
OPEN cur_custid FOR
SELECT '0' AS empid FROM dual;
ELSE
dbms_output.put_line('Non-zero Rows Condition Met. Re-opening Cursor.');
OPEN cur_custid FOR
SELECT DISTINCT firstname
,lastname
FROM temp_emp
WHERE JOB = var_job; /* Data Analyst does not exist forcing Zero Rows returned */
END IF;
В этом случае вам действительно нужно сделать только одну выборку в цикле и немедленно выйти; или вообще не зацикливайтесь, просто делайте одну простую выборку. Вас интересует только ноль / ненулевое значение, а не фактическое ненулевое значение.
db <> fiddle с вашим исходным кодом, новая версия с открытием второго курсора и вторая новая версия с одной выборкой. И слегка модифицированные вызывающие блоки для вывода результатов через dbms_output
.
Может быть проще сделать начальный подсчет и решить, какой курсор открыть.
Странно, что два возможных курсора имеют разное количество столбцов, между прочим. Предположительно, что бы это ни вызывало, оно должно проходить через курсор, и если он видит ноль в столбцах идентификаторов, он знает, что данных нет? Было бы намного чище просто , чтобы отмечал, обрабатывает ли он какие-либо строки. Тогда вашей процедуре не нужна эта логика, она может просто открыть единственный значащий курсор - если вам действительно нужна процедура для этого вообще. (Ваш реальный сценарий может выполнять гораздо больше работы, чем предполагает ваш пример; в этом случае подход подсчета все еще будет более уместным.)