Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not able to compile PL/SQL with BULK COLLECT and FORALL

I am getting below error while creating this procedure.

CREATE OR replace PROCEDURE Remove_sv_duplicate
IS
  TYPE sv_bulk_collect
    IS TABLE OF tt%ROWTYPE;
  sv_rec SV_BULK_COLLECT;
  CURSOR cur_data IS
    SELECT *
    FROM   tt
    WHERE  ROWID IN (SELECT ROWID
                     FROM   (SELECT ROWID,
                                    Row_number () over (PARTITION BY portingtn,
                                    nnsp
                                    , onsp,
                                    spid,
                                    Trunc(
                                            createddate,
                                    'MI') ORDER BY portingtn) dup
                             FROM   tt)
                     WHERE  dup > 1);
BEGIN
  OPEN cur_data;

  LOOP
      FETCH cur_data BULK COLLECT INTO sv_rec LIMIT 1000;

      FORALL i IN 1..sv_rec.COUNT
        INSERT INTO soa_temp_sv_refkey_fordelete
                    (referencekey,
                     spid,
                     nnsp,
                     onsp,
                     portingtn)
        (SELECT referencekey,
                spid,
                nnsp,
                onsp,
                portingtn
         FROM   tt
         WHERE  portingtn = Sv_rec(i).portingtn
                AND spid = Sv_rec(i).spid
                AND nnsp = Sv_rec(i).nnsp
                AND onsp = Sv_rec(i).onsp
                AND svid IS NULL);

      EXIT WHEN cur_data%notfound;
  END LOOP;

  CLOSE cur_data;

  COMMIT;
END; 

Procedure

Error(23,5): PL/SQL: SQL Statement ignored  
Error(25,27): PLS-00382: expression is of wrong type  
Error(25,27): PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records  
Error(26,27): PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records  
Error(26,27): PLS-00382: expression is of wrong type   
Error(27,27): PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records        
Error(27,27): PLS-00382: expression is of wrong type   
Error(28,27): PL/SQL: ORA-22806: not an object or REF    
Error(28,27): PLS-00382: expression is of wrong type  
Error(28,27): PLS-00436: implementation restriction: cannot reference fields of BULK In-BIND table of records
like image 418
praveen Avatar asked Nov 17 '11 15:11

praveen


1 Answers

You cannot* reference individual fields when you're using FORALL - that's why you get the PLS-00436 error.

To get around this, you will have to make use of associative arrays to refer individual fields.

DECLARE

    TYPE tt_rectype IS RECORD (
      referencekey tt.referencekey%TYPE,
      spid tt.spid%TYPE,
      nnsp tt.hiredate%TYPE,
      onsp tt.deptno%TYPE,
      portingtn tt.portingtn%TYPE);

    TYPE tt_aa_type
      IS TABLE OF TT_RECTYPE INDEX BY PLS_INTEGER;

    tt_aa TT_AA_TYPE;
    CURSOR cur_data IS
      SELECT *
      FROM   tt
      WHERE  ROWID IN (SELECT ROWID
                       FROM   (SELECT ROWID,
                                      Row_number () over (PARTITION BY portingtn
                                      ,
                                      nnsp
                                      , onsp,
                                      spid,
                                      Trunc(
                                              createddate
                                      , 'MI') ORDER BY portingtn) dup
                               FROM   tt)
                       WHERE  dup > 1);
BEGIN
    OPEN cur_data;

    LOOP
        FETCH cur_data BULK COLLECT INTO tt_aa LIMIT 1000;

        FORALL i IN 1..tt_aa.COUNT
          INSERT INTO soa_temp_sv_refkey_fordelete
                      (referencekey,
                       spid,
                       nnsp,
                       onsp,
                       portingtn)
          (SELECT referencekey,
                  spid,
                  nnsp,
                  onsp,
                  portingtn
           FROM   tt
           WHERE  portingtn = Tt_aa(i).portingtn
                  AND spid = Tt_aa(i).spid
                  AND nnsp = Tt_aa(i).nnsp
                  AND onsp = Tt_aa(i).onsp
                  AND svid IS NULL);

        EXIT WHEN cur_data%notfound;
    END LOOP;

    CLOSE cur_data;

    COMMIT;
END; 

*note this limitation is no longer present in Oracle 11g+


In addition, as @jonearles comments, you could just use a single SQL statement....

INSERT INTO soa_temp_sv_refkey_fordelete
            (referencekey,
             spid,
             nnsp,
             onsp,
             portingtn)
SELECT referencekey,
       spid,
       nnsp,
       onsp,
       portingtn
FROM   tt
WHERE  ROWID IN (SELECT ROWID
                 FROM   (SELECT ROWID,
                                Row_number () over (PARTITION BY portingtn, nnsp
                                , onsp,
                                spid,
                                Trunc(
                                        createddate
                                , 'MI') ORDER BY portingtn) dup
                         FROM   tt)
                 WHERE  dup > 1); 
like image 159
Sathyajith Bhat Avatar answered Oct 12 '22 03:10

Sathyajith Bhat