Ошибка при извлечении курсора таблицы объектов

#arrays #oracle #plsql

Вопрос:

Я новичок в изучении PLSQL и определенно новичок в типе объектов (абстрактных типах данных) в PLSQL. Так или иначе, я увидел код в своей компании, использующий оператор таблицы при определении курсора, поэтому я подумал попробовать это. В следующем анонимном блоке я получаю ошибку «PLS-00386: несоответствие типа, найденное в» V_CU», между курсором ВЫБОРКИ и переменными», но когда я использую c%rowtype (прокомментированная часть) вместо obj_emp при объявлении V_CU, я не получаю эту ошибку. Я не могу понять причину этой ошибки.

В конце концов, строка курсора c состоит из одного элемента объекта obj_emp, не так ли?

 CREATE OR REPLACE TYPE obj_emp IS OBJECT (
    first_name  VARCHAR2(80),
    last_name   VARCHAR2(80),
    salary      NUMBER
);
/
CREATE OR REPLACE TYPE tab_emp_t IS TABLE OF obj_emp;
/

declare
    v_num number:=60;
    tab_emp tab_emp_t :=tab_emp_t();
    cursor c is select * from table(tab_emp);
    v_cu obj_emp --c%rowtype
    ;
      
begin

    for i in (select * from employees_copy where department_id = v_num) loop
        tab_emp.extend;
        tab_emp(tab_emp.last):=obj_emp(i.first_name, i.LAST_NAME, i.salary);
    end loop;
    
    open c;
    loop
        fetch c into v_cu;
        exit when c%notfound;
        dbms_output.put_line(v_cu.first_name||' '||v_cu.last_name||' earns '||v_cu.salary);
    end loop;
    close c;
end;
/
 

Ответ №1:

Ожидается ошибка; она исправлена, если вы раскомментируете v_cu тип данных — он все равно должен быть c%rowtype .

Но я думаю, что вы хотели попробовать показать значения, хранящиеся в коллекции. Если это так, взгляните на следующий код (немного изменив то, что вы написали; у меня нет ваших таблиц, поэтому я использовал EMP вместо них таблицы Скотта).

 SQL> declare
  2      v_num number:=10;
  3      tab_emp tab_emp_t :=tab_emp_t();
  4      v_cnt number:=1;
  5      cursor c is select * from table(tab_emp);
  6      v_cu c%rowtype; --obj_emp --c%rowtype
  7
  8  begin
  9      dbms_output.put_line('-------- Store values into a collection ---------');
 10      for i in (select * from emp where deptno = v_num) loop
 11          tab_emp.extend;
 12          tab_emp(v_cnt):=obj_emp(i.ename, i.job, i.sal);
 13          v_cnt:=v_cnt 1;
 14      end loop;
 15      v_cnt:=1;
 16
 17      dbms_output.put_line('-------- Display values from a cursor -----------');
 18      open c;
 19      loop
 20          fetch c into v_cu;
 21          exit when c%notfound;
 22          dbms_output.put_line(v_cu.first_name||' '||v_cu.last_name||' earns '||v_cu.salary);
 23      end loop;
 24
 25      dbms_output.put_line('-------- Display values from a collection -------');
 26
 27      for i in tab_emp.first .. tab_emp.last loop
 28        dbms_output.put_Line(tab_emp(i).first_name ||' '|| tab_emp(i).last_name ||' earns ' || tab_emp(i).salary);
 29      end loop;
 30  end;
 31  /
 

Результаты в

 -------- Store values into a collection ---------
-------- Display values from a cursor -----------
CLARK MANAGER earns 2450
KING PRESIDENT earns 5000
MILLER CLERK earns 1300
-------- Display values from a collection -------
CLARK MANAGER earns 2450
KING PRESIDENT earns 5000
MILLER CLERK earns 1300

PL/SQL procedure successfully completed.

SQL>
 

Комментарии:

1. Спасибо Литтлфут за то, что уделили мне время. Я просто хотел правильно извлечь данные из курсора и, вероятно, отобразить значения из курсора. Мой вопрос, который остается без ответа, заключается в том, какой именно тип правильного v_cu. Как это не obj_emp? и каков тип c%rowtype, если он отличается от obj_emp?

2. V_CU является переменной курсора и должна принимать значения, возвращаемые курсором, поэтому ее тип данных-C%ROWTYPE. Взгляните на статью Стивена Фейерштейна здесь ( blogs.oracle.com/oraclemagazine/working-with-cursors ) для получения дополнительной информации и примеров.

3. Привет, Лайтфут, я проверил эту статью, но, думаю, вы не поняли мой вопрос. Я знаю, что когда я объявляю v_cu как тип строки курсора c, это работает нормально, но когда я явно объявляю v_cu как obj_emp, это не работает. Мой вопрос в том, что на самом деле является типом c%rowtype, если не obj_emp? Курсор выбирается из коллекции объектов obj_emp, поэтому я не ошибусь, предположив, что каждая строка курсора c в основном является obj_emp, и, следовательно, я не ошибусь, если получу строки курсора c в переменный экземпляр v_cu obj_emp. Но, увы, я не могу этого сделать!!!