ORA-00932: несогласованные типы данных: ожидалось - получено -

Я использую Oracle (10g.2) в качестве программиста PHP почти 3 года, но когда я дал задание, я впервые попытался использовать курсоры ref и типы коллекций. И я искал в Интернете, когда столкнулся с проблемами, и эта ошибка ora-00932 действительно поразила меня. Мне нужна старая рука.

Вот то, с чем я занимался: я хочу выбрать строки из таблицы и поместить их в указатель ref, а затем, используя тип записи, собрать их в ассоциативный массив. И снова из этого ассоциативного массива сделайте указатель ref. Не спрашивайте меня, почему, я пишу такой сложный код, потому что он мне нужен для более сложных заданий. Я могу вас сбить с толку, поэтому позвольте мне показать вам свои коды.

У меня есть 2 типа, определенные на вкладке типов в Toad. Один из них - объектный тип:

CREATE OR REPLACE
TYPE R_TYPE AS OBJECT(sqn number,firstname VARCHAR2(30), lastname VARCHAR2(30));

Другой тип коллекции, который использует тип объекта, созданный выше:

CREATE OR REPLACE
TYPE tr_type AS TABLE OF r_type;

Затем создаю пакет:

CREATE OR REPLACE PACKAGE MYPACK_PKG IS
TYPE MY_REF_CURSOR IS REF CURSOR;
PROCEDURE MY_PROC(r_cursor OUT MY_REF_CURSOR);
END MYPACK_PKG;

Тело пакета:

CREATE OR REPLACE PACKAGE BODY MYPACK_PKG AS
 PROCEDURE MY_PROC(r_cursor OUT MY_REF_CURSOR) AS
  rcur MYPACK_PKG.MY_REF_CURSOR;
  sql_stmt VARCHAR2(1000);
  l_rarray   tr_type := tr_type();
                l_rec r_type;

 BEGIN
     sql_stmt :=  'SELECT 1,e.first_name,e.last_name  FROM hr.employees e ';
     OPEN rcur FOR sql_stmt;
     LOOP
       fetch rcur into l_rec;
                  exit when rcur%notfound;
     l_rarray := tr_type( l_rec );
     END LOOP;
   CLOSE rcur;
    --OPEN r_cursor FOR SELECT * FROM TABLE(cast(l_rarray as tr_type) );


END MY_PROC;
END MYPACK_PKG;

Я закомментировал последнюю строку, в которой открываю указатель ref. Потому что это вызывает еще одну ошибку, когда я запускаю процедуру в редакторе SQL Toad, и это второй вопрос, который я задам. И, наконец, я запускаю код в Toad:

variable r refcursor
declare
r_out MYPACK_PKG.MY_REF_CURSOR;
begin
MYPACK_PKG.MY_PROC(r_out);
:r := r_out;
end;
print :r

Там я получаю ошибку ora-00932.


person Duygu Akyol    schedule 04.01.2011    source источник


Ответы (1)


Вы используете REF CURSOR необычно. Это будет стандартный способ их использования:

SQL> CREATE OR REPLACE PACKAGE BODY MYPACK_PKG AS
  2     PROCEDURE MY_PROC(r_cursor OUT MY_REF_CURSOR) AS
  3     BEGIN
  4        OPEN r_cursor FOR SELECT e.empno,e.ENAME,null  FROM scott.emp e;
  5     END MY_PROC;
  6  END MYPACK_PKG;
  7  /

Corps de package crÚÚ.

SQL> VARIABLE r REFCURSOR
SQL> BEGIN
  2     MYPACK_PKG.MY_PROC(:r);
  3  END;
  4  /

ProcÚdure PL/SQL terminÚe avec succÞs.

SQL> PRINT :r

     EMPNO ENAME      N
---------- ---------- -
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      [...]

14 ligne(s) sÚlectionnÚe(s).

Я не уверен, что вы здесь пытаетесь сделать, вы выбираете курсор ref внутри процедуры, а затем возвращаете другой курсор ref, который будет иметь те же данные. Я не думаю, что в процедуре вообще есть необходимость наводить курсор. Позвольте вызывающему приложению выполнять выборку (здесь выборка выполняется print).

Обновление: почему вы получаете бесполезное сообщение об ошибке?

Вы используете курсор, который открывается динамически, и я думаю, что это одна из причин, по которой вы получаете бесполезное сообщение об ошибке. Если мы используем фиксированный SQL, сообщение об ошибке будет другим:

SQL> CREATE OR REPLACE PACKAGE BODY MYPACK_PKG AS
  2     PROCEDURE MY_PROC(r_cursor OUT MY_REF_CURSOR) AS
  3        TYPE type_rec IS RECORD (qn number,
  4                                 firstname VARCHAR2(30),
  5                                 lastname VARCHAR2(30));
  6        lt_record type_rec; /* Record type */
  7        lt_object r_type; /* SQL Object type */
  8     BEGIN
  9        OPEN r_cursor FOR SELECT e.empno,e.ENAME,null  FROM scott.emp e;
 10        FETCH r_cursor INTO lt_record; /* This will work */
 11        FETCH r_cursor INTO lt_object; /* This won't work in 10.2 */
 12     END MY_PROC;
 13  END MYPACK_PKG;
 14  /

Package body created

SQL> VARIABLE r REFCURSOR
SQL> BEGIN
  2     MYPACK_PKG.MY_PROC(:r);
  3  END;
  4  /
BEGIN
*
ERREUR Ó la ligne 1 :
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at "APPS.MYPACK_PKG", line 11
ORA-06512: at line 2

Я отметил, что в настоящее время в версии 10.2 вы можете выбрать курсор в записи PLSQL, но не в объекте SQL.

Обновление: относительно PLS-00306: неправильное количество или типы аргументов

l_rarray - это ВЛОЖЕННАЯ ТАБЛИЦА, ее нужно инициализировать, а затем расширить, чтобы можно было хранить элементы. Например:

SQL> CREATE OR REPLACE PACKAGE BODY MYPACK_PKG AS
  2     PROCEDURE MY_PROC(r_cursor OUT MY_REF_CURSOR) AS
  3        lr_array tr_type := tr_type(); /* SQL Array */
  4     BEGIN
  5        FOR cc IN (SELECT e.empno, e.ENAME, NULL lastname
  6                     FROM scott.emp e) LOOP
  7           lr_array.extend;
  8           lr_array(lr_array.count) := r_type(cc.empno,
  9                                              cc.ename,
 10                                              cc.lastname);
 11           /* Here you can do additional procedural work on lr_array */
 12        END LOOP;
 13        /* then return the result set */
 14        OPEN r_cursor FOR SELECT * FROM TABLE (lr_array);
 15     END MY_PROC;
 16  END MYPACK_PKG;
 17  /

Corps de package crÚÚ.

SQL> print r

       SQN FIRSTNAME                      LASTNAME
---------- ------------------------------ -----------
      7369 SMITH                          
      7499 ALLEN                          
      7521 WARD                           
      [...]

14 ligne(s) sÚlectionnÚe(s).

Для дальнейшего чтения вы можете просмотреть документацию по коллекциям и записям PL / SQL < / а>.

person Vincent Malgrat    schedule 04.01.2011
comment
Спасибо за ваш ответ, но, как я уже упоминал ранее, это всего лишь простой пример, реальная проблема более сложная, и рефкурсор, который указан в части объявления процедуры, и параметр out, который возвращает результаты, который является другим указателем ref, выигранным не содержать те же данные в фактическом случае. - person Duygu Akyol; 04.01.2011
comment
Большое спасибо за ответ. С помощью вашего кода я объявил свой тип записи внутри процедуры, и это единственное изменение, которое я внес в код, и ошибка исчезла. Хотя это помогло мне исправить ошибку, я начал получать другую ошибку. Он находится в строке, где я идентифицирую свой ассоциативный массив с записью типа (l_rarray: = tr_type (l_rec);), а ошибка - PLS-00306: неправильное количество или типы аргументов при вызове TR_TYPE. Вы знаете, почему произошла ошибка? - person Duygu Akyol; 04.01.2011
comment
Большое спасибо. Теперь я понял, что нет необходимости извлекать указатель ref в тип записи, и решил ошибку, выполнив то, что вы описали в своем последнем сообщении. Еще раз спасибо и еще раз. - person Duygu Akyol; 04.01.2011
comment
Я хочу задать вам еще один вопрос, надеюсь, он будет последним. В вашем последнем посте, если вы используете динамический sql, например 'sql_stmt: = SELECT e.empno, e.ENAME, NULL lastname FROM scott.emp e' , а затем FOR cc IN (выберите sql_stmt FROM dual), а затем попытайтесь достичь элементов курсора, написав, например, cc.empno, вы получите ошибку PLS-00302. Как вы можете с этим справиться? Есть ли способ, потому что мне нужно использовать динамический sql. - person Duygu Akyol; 05.01.2011
comment
@duygu: Если вы используете динамический SQL, вам придется использовать явный курсор, например: DECLARE lc SYS_REFCURSOR; ldummy VARCHAR2(1); BEGIN OPEN lc FOR 'SELECT * FROM DUAL'; FETCH lc INTO ldummy; CLOSE lc;END; - person Vincent Malgrat; 05.01.2011