ORA-06511: PL/SQL: 游标已经打开 即使在关闭之后

ORA-06511: PL/SQL: cursor already open Even after closing

我已经创建了一个程序包,这样:

 PROCEDURE person_phone_data_load
   IS
      CURSOR cur_phone_info
      is
         SELECT itnpi.ROWID row_id, itnpi.*
           from xx_TAL_NEWHIRE_PHONE_INT ITNPI,
             xx_tal_newhire_employ_int emp
          where 1 = 1 and ITNPI.STATUS in ('N', 'E')
               and EMP.CANDIDATE_NUMBER=ITNPI.CANDIDATE_NUMBER
            and BUSINESS_UNIT='APGEN BUSINESS GROUP'
          ;
/**
select phone.ROWID row_id, phone.candidate_number, DECODE(phone.phone_type,'Work Phone','WORK','Home Phone','HOME','Cellular Phone','MOBILE',phone.phone_type) PHONE_TYPE,
       case phone.phone_type
           when 'Mobile Phone' then mobile_number
           when 'Work Phone'   then WORK_PHONE 
           when 'Home Phone'   then home_number
           end   as phone_number
from xx_tal_newhire_phone_int phone
 Where 1 = 1 And Phone.Status In ('N', 'E'); 
 **/
      CURSOR lcu_get_person_id (p_candidate_number VARCHAR2)
      IS
         SELECT   papf.person_id, papf.start_date
             FROM per_all_people_f papf, per_people_extra_info ppei
            WHERE papf.person_id = ppei.person_id
              AND ppei.information_type = 'XXHR_TAL_NEWHIRE_READER'
              AND ppei.pei_information1 = p_candidate_number
              AND papf.effective_start_date =
                                    (SELECT MAX (papf1.effective_start_date)
                                       FROM per_all_people_f papf1
                                      WHERE papf1.person_id = papf.person_id)
         GROUP BY papf.person_id, papf.start_date;

      CURSOR lcu_check_phone (p_personid NUMBER, p_phone_type VARCHAR2)
      IS
         SELECT phone_number
           FROM per_phones
          WHERE SYSDATE BETWEEN date_from AND NVL (date_to, '31-DEC-4712')
            AND phone_type = p_phone_type
            AND parent_id = p_personid;

      lv_phone_type              VARCHAR2 (240);
      ln_phone_type_excep        VARCHAR2 (2000);
      an_phone_type_excep        VARCHAR2 (2000);
      ln_phone_id                NUMBER;
      ln_object_version_number   NUMBER;
      ld_ph_date_from            DATE;
      ld_ph_date_to              DATE;
      lv_phone_number            VARCHAR2 (100);    

      ln_person_id               NUMBER;
      ln_phone_err_msg           VARCHAR2 (2000);
      ln_person_excep            VARCHAR2 (2000);
      an_person_excep            VARCHAR2 (2000);
      lc_rec_status              VARCHAR2 (1);
      ln_phoneno                 NUMBER;
      ln_start_date               DATE;
   BEGIN
      fnd_file.put_line (fnd_file.LOG,
                         '**********************************************'
                        );
      fnd_file.put_line (fnd_file.LOG,
                         '** New Hire Phone load Program Starts **'
                        );

      FOR phone_info_rec IN cur_phone_info
      LOOP
         BEGIN
            lv_phone_type := NULL;
            ln_phone_id := NULL;
            ln_object_version_number := NULL;
            ln_person_id := NULL;
            ln_phone_err_msg := NULL;
            ld_ph_date_from := TRUNC (SYSDATE);
            ld_ph_date_to := NULL;
            lv_phone_number := phone_info_rec.phone_number ;

            ln_phone_type_excep := NULL;
            ln_person_excep := NULL;
            lc_rec_status := 'S';

            IF phone_info_rec.phone_type IS NOT NULL
            THEN
               lv_phone_type :=
                     get_lookup_code ('PHONE_TYPE', phone_info_rec.phone_type);

               IF lv_phone_type = 'NO_VALUE'
               THEN
                  lc_rec_status := 'E';
                  -- Could not decode the SEX for the Employee.
                  ln_phone_err_msg :=
                        ln_phone_err_msg
                     || 'Invalid Phone Type for candidate_number: '
                     || phone_info_rec.candidate_number
                     || ' # ';
               END IF;
            END IF;

            IF phone_info_rec.candidate_number IS NOT NULL
            THEN
               ln_person_id := NULL;

               OPEN lcu_get_person_id (phone_info_rec.candidate_number);

               FETCH lcu_get_person_id
                INTO ln_person_id, ln_start_date;

               CLOSE lcu_get_person_id;

               IF ln_person_id IS NULL
               THEN
                  lc_rec_status := 'E';
                  -- Employee Not Created for the Candidate Number.
                  ln_phone_err_msg :=
                        ln_phone_err_msg
                     || 'Employee Record not created for the candidate_number: '
                     || phone_info_rec.candidate_number
                     || ' # ';
               ELSIF ln_person_id IS NOT NULL
               THEN
                  OPEN lcu_check_phone (ln_person_id, lv_phone_type);

                  FETCH lcu_check_phone
                   Into Ln_Phoneno;
   Close lcu_check_phone;

         If Lcu_Check_Phone%Isopen Then
                        Close Lcu_Check_Phone;
                        END IF; 
                  IF ln_phoneno = phone_info_rec.phone_number
                  Then
                     lc_rec_status := 'P';
                     ln_phone_err_msg :=
                           ln_phone_err_msg
                        || 'Phone already exists for the candidate_number:  '
                        || phone_info_rec.candidate_number
                        || ' # ';


                  END IF;


               END IF;
            ELSE
               lc_rec_status := 'E';
               -- Candidate Number is NULL.
               ln_phone_err_msg :=
                     ln_phone_err_msg
                  || 'Candidate Number is NULL; So Could not find the Employee for Address creation';
            END IF;

            IF lc_rec_status = 'S'
            THEN
               BEGIN

                  UPDATE xx_tal_newhire_phone_int iph
                     SET status = 'P',
                         error_msg = NULL
                   WHERE iph.ROWID = phone_info_rec.row_id;

                  COMMIT;
                  fnd_file.put_line
                     (fnd_file.LOG,
                         'Successfully Processed phone record for candidate_number: '
                      || phone_info_rec.candidate_number
                     );
               EXCEPTION
                  WHEN OTHERS
                  THEN
                     ln_phone_err_msg :=
                           'Phone API Error while processing candidate_number: '
                        || phone_info_rec.candidate_number
                        || ' , '
                        || SUBSTR (SQLERRM, 1, 150);

                     UPDATE xx_tal_newhire_phone_int iph
                        SET status = 'E',
                            error_msg = ln_phone_err_msg
                      WHERE iph.ROWID = phone_info_rec.row_id;

                     fnd_file.put_line
                        (fnd_file.LOG,
                            'Person API Error while processing candidate_number: '
                         || phone_info_rec.candidate_number
                         || ' , '
                         || SUBSTR (SQLERRM, 1, 150)||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE()
                        );
               END;
            ELSE
               UPDATE xx_tal_newhire_phone_int iph
                  SET status = lc_rec_status,
                      error_msg = ln_phone_err_msg
                WHERE iph.ROWID = phone_info_rec.row_id;
            END IF;

            COMMIT;
         EXCEPTION
            WHEN OTHERS
            THEN
               ln_phone_err_msg :=
                                 'Phone Error : ' || SUBSTR (SQLERRM, 1, 150)||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE();

               Update xx_Tal_Newhire_Phone_Int Iph
                  SET status = 'E',
                      error_msg = ln_phone_err_msg
                WHERE iph.ROWID = phone_info_rec.row_id;

               COMMIT;
         END;
      End Loop;

      fnd_file.put_line (fnd_file.LOG,
                         '** New Hire Phone load Program Ends **'
                        );
   EXCEPTION
      WHEN OTHERS
      THEN
         fnd_file.put_line (fnd_file.LOG,
                            'In phone main :' || SUBSTR (SQLERRM, 1, 150)
                           );
         ROLLBACK;
   END person_phone_data_load;

我得到一个:"Phone Error : ORA-06511: PL/SQL: cursor already open

log.This 中的错误是针对游标 lcu_check_phone 的。我还明确添加了一个 if 语句以在打开时关闭游标。我仍然收到此错误。

我认为你遇到的问题是这个

              OPEN lcu_check_phone (ln_person_id, lv_phone_type);

              FETCH lcu_check_phone
               Into Ln_Phoneno;
              Close lcu_check_phone;

Phone 数字不是数字字段 - 但 Ln_Phoneno 被定义为数字。您的 fetch 语句抛出一个已处理的异常,但这会绕过您的两个 close 语句。然后在下一次迭代中您将无法重新打开游标。

如果您要使用所有这些嵌套循环,那么您需要在异常处理程序中放置关闭语句。

另一种方法是更加模块化——使用一些小过程来分解你的代码——这样你就不必太担心范围,因为每个游标只会在单次迭代期间存在.如果这有意义...

为避免 open/close/fetch 游标问题,请尽可能使用游标循环。您不必担心一次性从游标中获取所有值,也不必担心循环计数,因为它由循环本身控制(就像其他语言的 for:each 循环)。我通常使用标准 open/fetch/close 来检查游标是否加载了一些数据,如果不加载,它会将 %NOTFOUND 标志设置为 true,这在错误处理中很有用,与 select 相反,将 NO_DATA_FOUND 没有数据 selected。