sqloracle-databaseplsqlref-cursor

can TYPE be declared of ref cursor rowtype


 TYPE ref_cur IS REF CURSOR;
 ref_cur_name    ref_cur;
 TYPE tmptbl IS  TABLE OF ref_cur_name%ROWTYPE;
 n_tmptbl        tmptbl;

I tried this code but can't get it thru compiler . Is there a way to store the results of ref cursor into a table ?

NOTE-I need a table because i need to access the column of ref cursor . Using dbms_sql to access records of ref cursor is a bit tough for me .

UPDATE :

/* Formatted on 8/1/2013 4:09:08 PM (QP5 v5.115.810.9015) */
CREATE OR REPLACE PROCEDURE proc_deduplicate (p_tblname   IN VARCHAR2,
                                               p_cname     IN VARCHAR2,
                                               p_cvalue    IN VARCHAR2)
IS
   v_cnt          NUMBER;

   TYPE ref_cur IS REF CURSOR;
   ref_cur_name   ref_cur;


   v_str1         VARCHAR2 (4000);
   v_str2         VARCHAR2 (4000);
   v_str3         VARCHAR2 (4000);
BEGIN
   v_str1 :=
         'SELECT ROWID v_rowid FROM '
      || p_tblname
      || ' WHERE '
      || p_cname
      || '='''
      || p_cvalue
      || '''';


   BEGIN
      v_str2 :=
            'SELECT   COUNT ( * )

         FROM  '
         || p_tblname
         || ' WHERE  '
         || p_cname
         || ' = '''
         || p_cvalue
         || '''';
      logerrors ('proc_deduplicate',
                 'count exception',
                 SQLCODE,
                 v_str2 || SQLERRM,
                 'e');

      EXECUTE IMMEDIATE v_str2 INTO   v_cnt;
   EXCEPTION
      WHEN OTHERS
      THEN
         logerrors ('proc_deduplicate',
                    'count exception',
                    SQLCODE,
                    SQLERRM,
                    'e');
   END;

   IF v_cnt IS NOT NULL
   THEN
     OPEN ref_cur_name FOR v_str1;

      LOOP
         IF v_cnt = 1
         THEN
            EXIT;
         ELSE
            BEGIN
               v_str3 :=
                     'DELETE FROM '
                  || p_tblname
                  || ' WHERE   ROWID = v_rowid '; 
 -- THIS IS THE PROBLEM . i just created an alias above for rowid keyword but i guess, DBMS sql will have to be used  after all . 


               EXECUTE IMMEDIATE v_str3;
            EXCEPTION
               WHEN OTHERS
               THEN
                  logerrors (
                     '                                                            proc_deduplicate
      ',
                     '                                                            delete exception
      ',
                     SQLCODE,
                     SQLERRM,
                     '                                                            e
      '
                  );
            END;
         END IF;

         v_cnt := v_cnt - 1;
      END LOOP;
   END IF;
EXCEPTION
   WHEN OTHERS
   THEN
      logerrors (
         '                                    proc_deduplicate',
         '                                    final exception
      ',
         SQLCODE,
         SQLERRM,
         '                                    e'
      );
END;
/

Solution

  • As far as I understand what you're doing, you just need to parameterise the delete:

    ...
       v_str3         VARCHAR2 (4000);
       v_rowid        ROWID;
    BEGIN
    ...
         OPEN ref_cur_name FOR v_str1;
    
          LOOP
             FETCH ref_cur_name INTO v_rowid;
             EXIT WHEN ref_cur_name%NOTFOUND;
             IF v_cnt = 1
             THEN
                EXIT;
             ELSE
                BEGIN
                   v_str3 :=
                         'DELETE FROM '
                      || p_tblname
                      || ' WHERE   ROWID = :v_rowid '; 
    
                   EXECUTE IMMEDIATE v_str3 USING v_rowid;
    ...
    

    You need to fetch the ref_cur_name into a variable, which needs to be declared obviously, and then use that as a bind variable value in the delete.

    You should do the same thing with the p_cvalue references in the other dynamic SQL too. You could probably make this much simpler, with a single delete and no explicit count, in a single dynamic statement:

    CREATE OR REPLACE PROCEDURE proc_deduplicate (p_tblname   IN VARCHAR2,
                                                   p_cname     IN VARCHAR2,
                                                   p_cvalue    IN VARCHAR2)
    IS
    BEGIN
       execute immediate 'delete from ' || p_tblname
          || ' where ' || p_cname || ' = :cvalue'
          || ' and rowid != (select min(rowid) from ' || p_tblname
              || ' where ' || p_cname || ' = :cvalue)'
          using p_cvalue, p_cvalue;
    END proc_deduplicate;
    /
    

    SQL Fiddle.

    If you wanted to know or report how many rows were deleted, you could refer to SQL%ROWCOUNT after the execute immediate.