ORA-01002: извлечение из последовательности в оракуле - PullRequest
0 голосов
/ 29 мая 2019

ORA-01002: выбор из последовательности в oracle при использовании sys_refcursor.

Я ожидаю список сотрудников в курсоре.В моем реальном сценарии мне нужно проверить количество сотрудников, и если число больше нуля, я должен использовать тот же оператор выбора.Вместо выполнения одного и того же оператора select несколько раз, я попробовал приведенный ниже фрагмент кода.Но я получаю ошибку Fetch out of sequence в выходном курсоре.

Моя таблица:

My table

create or replace procedure sp_temp_1  (
var_job in VARCHAR2,
cur_custid out sys_refcursor
) 
AS

  /* Declare Ref Cursor */
  --cur_custid  SYS_REFCURSOR;

  /* Declare Type using Fields from the employees table. */
  TYPE t_custrec IS RECORD (
    firstname    temp_emp.firstname%TYPE,
    lastname     temp_emp.lastname%TYPE
  );

  /* Declare Record based off of Type */
  custrec   t_custrec;

BEGIN

  OPEN cur_custid FOR
    SELECT DISTINCT firstname
                   ,lastname
      FROM temp_emp
     WHERE JOB = var_job; /* Data Analyst does not exist forcing Zero Rows returned */

  LOOP
    FETCH cur_custid
      INTO custrec;
    EXIT WHEN cur_custid%notfound;
    ---looping happens
  END LOOP;

  dbms_output.put_line('Num Rows: ' || cur_custid%rowcount);

  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;
  END IF;

END;

Я ожидаю список сотрудников, ноsys_refcursor предоставляет «ошибку извлечения из последовательности» в Oracle:

Screen shot of my error

Ответы [ 2 ]

1 голос
/ 30 мая 2019

Я не уверен, почему 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.

Может быть проще сделать начальный подсчет и решить, какой курсор открыть.

Странно, что два возможных курсора имеют разное количество столбцов, между прочим. Предположительно, что бы это ни вызывало, оно должно проходить через курсор, и если он видит ноль в столбцах идентификаторов, он знает, что данных нет? Было бы намного чище просто , чтобы отмечал, обрабатывает ли он какие-либо строки. Тогда вашей процедуре не нужна эта логика, она может просто открыть единственный значащий курсор - если вам действительно нужна процедура для этого вообще. (Ваш реальный сценарий может выполнять гораздо больше работы, чем предполагает ваш пример; в этом случае подход подсчета все еще будет более уместным.)

0 голосов
/ 30 мая 2019

Когда я использую ваш код с моими незначительными изменениями, я не получаю ошибку.Возможно, мой рабочий код может помочь вам?Дайте мне знать, если у вас есть какие-либо вопросы или я могу помочь вам в дальнейшем.

Резюме

  • Объявление курсора ссылки
  • Объявление типа на основеполей в таблице моих сотрудников
  • Объявить запись на основе типа
  • Открыть курсор и ввести Loop
  • В записи заполнения цикла с использованием значений FETCH, полученных курсором.
  • Использование dbms_output показывает некоторый вывод, поэтому мы знаем, что он работает
  • Наконец, если нулевые строки возвращаются курсором, снова откройте курсор, используя другой SQL.

Таблица сотрудников

enter image description here

Код

DECLARE

  /* Declare Ref Cursor */
  cur_custid  SYS_REFCURSOR;

  /* Declare Type using Fields from the employees table. */
  TYPE t_custrec IS RECORD (
    firstname    employees.firstname%TYPE,
    lastname     employees.lastname%TYPE
  );

  /* Declare Record based off of Type */
  custrec   t_custrec;

BEGIN

  OPEN cur_custid FOR
    SELECT DISTINCT firstname
                   ,lastname
      FROM employees
     WHERE JOB like '%Data Analyst%'; /* Data Analyst does not exist forcing Zero Rows returned */

  LOOP
    FETCH cur_custid
      INTO custrec;
    EXIT WHEN cur_custid%notfound;
    ---looping happens
  END LOOP;

  dbms_output.put_line('Num Rows: ' || cur_custid%rowcount);

  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;
  END IF;

END;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...