Why can't we use strong ref cursor with dynami

2020-02-13 03:02发布

问题:

I am trying to use a strong ref cur with dynamic sql statment but it is giving out an error,but when i use weak cursor it works,Please explain what is the reason and please forward me any link of oracle server architect containing matter about how compilation and parsing is done in Oracle server. THIS is the error along with code.

ERROR at line 6:
ORA-06550: line 6, column 7:
PLS-00455: cursor 'EMP_REF_CUR' cannot be used in dynamic SQL OPEN statement
ORA-06550: line 6, column 2:
PL/SQL: Statement ignored

declare
      type ref_cur_type IS REF CURSOR RETURN employees%ROWTYPE; --Creating a strong REF cursor,employees is a table
     emp_ref_cur ref_cur_type;
     emp_rec employees%ROWTYPE;
BEGIN      
   OPEN emp_ref_cur FOR 'SELECT * FROM employees';
           LOOP
                   FETCH emp_ref_cur INTO emp_rec;
                   EXIT WHEN emp_ref_cur%NOTFOUND;
           END lOOP;       
END;

回答1:

Here is a procedure with a strongly-typed ref cursor:

SQL> create or replace procedure p1 is
  2      type dept_rc is ref cursor return dept%rowtype;
  3      my_ref_cursor dept_rc;
  4  begin
  5      open my_ref_cursor for
  6          select * from dept;
  7  end;
  8  /

Procedure created.

SQL>

This next statement fails because the signature of the EMP record doesn't match that of DEPT table.

SQL> create or replace procedure p1 is
  2      type dept_rc is ref cursor return dept%rowtype;
  3      my_ref_cursor dept_rc;
  4  begin
  5      open my_ref_cursor for
  6          select * from emp;
  7  end;
  8  /

Warning: Procedure created with compilation errors.

SQL> show error
Errors for PROCEDURE P1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: SQL Statement ignored
6/9      PLS-00382: expression is of wrong type

SQL>

But if we change the projection to match the DEPT table then we have success again:

SQL> create or replace procedure p1 is
  2      type dept_rc is ref cursor return dept%rowtype;
  3      my_ref_cursor dept_rc;
  4  begin
  5      open my_ref_cursor for
  6          select deptno, ename, job from emp;
  7  end;
  8  /

Procedure created.

SQL>

So, why can't we use a strongly-typed ref-cursor with dynamic SQL?

SQL> create or replace procedure p1 is
  2      type dept_rc is ref cursor return dept%rowtype;
  3      my_ref_cursor dept_rc;
  4  begin
  5      open my_ref_cursor for
  6          'select * from dept';
  7  end;
  8  /

Warning: Procedure created with compilation errors.

SQL> show error
Errors for PROCEDURE P1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: Statement ignored
5/10     PLS-00455: cursor 'MY_REF_CURSOR' cannot be used in dynamic SQL
         OPEN statement

SQL>

Because the compiler cannot parse the string in the dynamic SQL statement. So it cannot assert that the columns in the query's projection match in number and datatype the signature of the ref cursor. Consequently it cannot validate the contract between the ref cursor variable and the query. It is even easier to understand why this cannot be allowed when we consider that the dynamic SQL statement could be assembled from a query on USER_TAB_COLUMNS.



回答2:

Another possibility is to declare and define a Record Type object to be a container for your query results. This could be useful if the query is a JOIN query, returning columns from several joined tables.

SQL> create or replace procedure p1 is
     /* Declare you destination data structure row container */
     TYPE TestRecTyp IS RECORD (
        deptno varchar(50),
        ename  varchar(50),
        job    varchar(50)
     );
     /* Define an instance of the record type */
     testrec TestRecTyp;

     type dept_rc is ref cursor; /*return dept%rowtype;*/
     my_ref_cursor dept_rc;
     begin
         open my_ref_cursor for 'select deptno,ename,job from emp';
         LOOP
             FETCH my_ref_cursor INTO testrec;
         EXIT WHEN my_ref_cursor%NOTFOUND;

             /* Do some operations with testrec*/

         END LOOP;
     end;

NOTE: You could use the above technique on a dynamically constructed SQL query statement by substituting 'select deptno,ename,job from emp' with a variable such as v_sql and update this variable with the SQL statement within the body of the procedure.



回答3:

You are not allowed to open a strongly typed ref cursor for a dynamic sql, as the oracle engine cannot check whether the structure of the dynamic sql is matching with that of the ref cursor's return type.