为啥我会收到 ORA-06531:对未初始化集合的引用?

Posted

技术标签:

【中文标题】为啥我会收到 ORA-06531:对未初始化集合的引用?【英文标题】:Why do I get ORA-06531: reference to uninitialized collection?为什么我会收到 ORA-06531:对未初始化集合的引用? 【发布时间】:2020-09-05 07:55:50 【问题描述】:

我想调用一个 PL/SQL 函数

select consult_trac.get_detail_dos_amo('12345') from dual

但我得到了错误:

java.sql.SQLException: ORA-06530: 引用未初始化的复合 ORA-06512: à 第 60 行的“CNSS_SERVICES.GET_DETAIL_DOS_AMO” (ret(v_counter).num_doss := DS_DT.NUM_DOSS;)

我的 PL/SQL 函数定义在包含所有类型的包中。

包定义:

CREATE OR REPLACE PACKAGE consult_trac AS

FUNCTION get_detail_dos_amo (p_num_doss VARCHAR2)
      RETURN tab_dos_t_amo;

END consult_trac;
/

CREATE OR REPLACE PACKAGE BODY consult_trac AS
    FUNCTION get_detail_dos_amo (p_num_doss VARCHAR2)
      RETURN tab_dos_t_amo
      IS
      CURSOR DOSS_DET (num_doss VARCHAR2) IS
        SELECT NUM_DOSS,
               DAT_DEP,
               NUM_IMMA,
               NUM_IND,
               P_DATE_ACTE,
               CODE_EVOP,
               LIB_EVOP,
               CODE_DR,
               LIB_DR,
               C_USER,
               C_GENCE,
               C_NIV,
               L_NIV,
               DAT_SUI,
               C_D_ETAT,
               L_D_ETAT,
               L_NAT,
               NUM_RECOM,
               ACCUSE,
               P_MONTANT,
               NUM_D_PARENT,
               P_INP_DOS,
               P_ICE_DOS,
               P_CIN,
               P_NOM,
               P_PRENOM,
               P_N_PAGE,
               P_D_SORTIE,
               P_C_CAT,
               P_C_SOURCE,
               C_ERROR
        FROM   TYP_DOSS_AMO
        WHERE  NUM_DOSS = p_num_doss;
      
      CURSOR SEL_MEDIC(num_doss   VARCHAR2) IS
        SELECT CODE_MEDIC, 
               NOMBRE 
        FROM DOSS_MEDIC
        WHERE NUM_DOSS = num_doss;
      
      CURSOR SEL_INP(num_doss   VARCHAR2) IS
        SELECT CODE_INP
        FROM DOSS_INP
        WHERE NUM_DOSS = num_doss;
        
      ret tab_dos_t_amo;
      ret_med tab_medic; 
      ret_inp tab_inp;
      v_counter number := 0;
      v_counter_med number := 0;
      v_counter_inp number := 0;
    BEGIN
      FOR DS_DT IN DOSS_DET(p_num_doss) 
            LOOP
                ret(v_counter).num_doss := DS_DT.NUM_DOSS;
                ret(v_counter).dat_dep := DS_DT.DAT_DEP;
                ret(v_counter).num_imma := DS_DT.NUM_IMMA;
                ret(v_counter).num_ind := DS_DT.NUM_IND;
                ret(v_counter).p_date_acte := DS_DT.P_DATE_ACTE;
                ret(v_counter).code_evop := DS_DT.CODE_EVOP;
                ret(v_counter).lib_evop := DS_DT.LIB_EVOP;
                ret(v_counter).code_dr := DS_DT.CODE_DR;
                ret(v_counter).lib_dr := DS_DT.LIB_DR;
                ret(v_counter).c_user := DS_DT.C_USER;
                ret(v_counter).c_gence := DS_DT.C_GENCE;
                ret(v_counter).c_niv := DS_DT.C_NIV;
                ret(v_counter).l_niv := DS_DT.L_NIV;
                ret(v_counter).dat_sui := DS_DT.DAT_SUI;
                ret(v_counter).c_d_etat := DS_DT.C_D_ETAT;
                ret(v_counter).l_d_etat := DS_DT.L_D_ETAT;
                ret(v_counter).l_nat := DS_DT.L_NAT;
                ret(v_counter).num_recom := DS_DT.NUM_RECOM;                
                ret(v_counter).accuse := DS_DT.ACCUSE;  
                ret(v_counter).p_montant := DS_DT.P_MONTANT;
                ret(v_counter).num_d_parent := DS_DT.NUM_D_PARENT;
                ret(v_counter).p_INP_dos := DS_DT.P_INP_DOS;
                ret(v_counter).p_ICE_dos := DS_DT.P_ICE_DOS;
                ret(v_counter).p_cin := DS_DT.P_CIN;
                ret(v_counter).p_nom := DS_DT.P_NOM;
                ret(v_counter).p_prenom := DS_DT.P_PRENOM;
                ret(v_counter).p_n_page := DS_DT.P_N_PAGE;
                ret(v_counter).p_d_sortie := DS_DT.P_D_SORTIE;
                ret(v_counter).p_c_cat := DS_DT.P_C_CAT;
                ret(v_counter).p_c_source := DS_DT.P_C_SOURCE;
                ret(v_counter).c_error := DS_DT.C_ERROR;
                
                FOR SM IN SEL_MEDIC(p_num_doss)
                    LOOP
                        ret_med(v_counter_med).code_medic := SM.CODE_MEDIC;
                        ret_med(v_counter_med).nombre := SM.NOMBRE;
                        v_counter_med := v_counter_med +1;
                    END LOOP;
                FOR SI IN SEL_INP(p_num_doss)
                    LOOP
                        ret_inp(v_counter_inp).code_inp := SI.CODE_INP;
                        v_counter_inp := v_counter_inp +1;
                    END LOOP;
                ret(v_counter).p_tab_medic := ret_med;
                ret(v_counter).p_tab_inp := ret_inp;
                v_counter := v_counter + 1;
            END LOOP;

        return ret;
    END;
   
END consult_trac;
/

类型:

create or replace TYPE MEDIC AS OBJECT (
    num_doss   VARCHAR2(9),
    code_medic VARCHAR2(10),
    nombre     NUMBER);

create or replace TYPE tab_medic IS TABLE OF MEDIC;

create or replace TYPE INP AS OBJECT (
    num_doss   VARCHAR2(9),
    code_inp   VARCHAR2(20));

create or replace TYPE tab_INP IS TABLE OF INP;

create or replace TYPE TYP_DOS_AMO AS OBJECT (
        num_doss   VARCHAR2(9),
        dat_dep    DATE,
        num_imma   VARCHAR2(13),
        num_ind    VARCHAR2(20),
        p_date_acte  DATE,
        code_evop  VARCHAR2(20),
        lib_evop   VARCHAR2(30),
        code_dr    VARCHAR2(20),
        lib_dr     VARCHAR2(30),
        c_user     VARCHAR2(20),
        c_gence    VARCHAR2(20),
        c_niv      VARCHAR2(20),
        l_niv      VARCHAR2(20),
        dat_sui    DATE,
        c_d_etat   VARCHAR2(20),
        l_d_etat   VARCHAR2(20),
        l_nat      VARCHAR2(30),
        num_recom  VARCHAR2(30),
        accuse     VARCHAR2(30),
        p_montant  VARCHAR2(20),
        num_d_parent VARCHAR2(9),
        p_INP_dos  VARCHAR2(20),
        p_ICE_dos  VARCHAR2(20),
        p_cin      VARCHAR2(10),
        p_nom      VARCHAR2(20),
        p_prenom   VARCHAR2(20),
        p_n_page   VARCHAR2(20),              
        p_d_sortie DATE,
        p_c_cat    VARCHAR2(15),
        p_c_source VARCHAR2(15),
        p_tab_medic tab_medic,
        p_tab_inp   tab_inp,
        c_error    INTEGER
);
    
create or replace TYPE tab_INP IS TABLE OF INP;

【问题讨论】:

完整的跟踪错误是:06531. 00000 - “对未初始化集合的引用” *原因:嵌套表或可变数组的元素或成员函数被引用(需要初始化集合)而没有集合已初始化。 *操作:使用适当的构造函数或整个对象赋值来初始化集合。 这些类型在哪里?在子句typ_dos_amo 的第一个游标中,一个表? 它们位于架构级别。 typ_dos_amo 是一种类型 您应该清楚地提及它,因为这两种类型的实现会有所不同。你确定你已经创建了一个同名的表和一个对象吗? 类型tab_dos_t_amo是如何定义的? 【参考方案1】:

嵌套表对象与关联数组不同,使用前必须先初始化。

这样

ret tab_dos_t_amo

可能需要

ret tab_dos_t_amo := tab_dos_t_amo();

现在你想给它添加元素,你需要给数组添加一个索引,例如

ret.extend;

现在允许您引用 ret(1)。

您没有向我们展示 tab_dos_t_amo 的定义,但我认为它是一个 dos_t_amo 表。所以该表中的每个条目都是一个对象,这意味着您的代码:

            ret(v_counter).num_doss := DS_DT.NUM_DOSS;
            ret(v_counter).dat_dep := DS_DT.DAT_DEP;
            ret(v_counter).num_imma := DS_DT.NUM_IMMA;

现在看起来像

            ret.extend;
            ret(v_counter) := dos_t_amo(
                                  DS_DT.DAT_DEP,
                                  DS_DT.NUM_IMMA,
                                  ...
                                  ...);

【讨论】:

虽然我已经像上面那样初始化了数组,但我也遇到了同样的错误。我也间歇性地出错。类型看起来像:创建或替换 TYPE T_TABLE_TYPE1 作为 T_TYPE2 的表;并在存储过程中使用它,例如: V_DATA T_TABLE_TYPE1 := T_TABLE_TYPE1(); SELECT V_DATA(1).field1 进入 field_data;

以上是关于为啥我会收到 ORA-06531:对未初始化集合的引用?的主要内容,如果未能解决你的问题,请参考以下文章

ORA-06531: 引用未初始化的收集 的问题解决

获取对关联数组的未初始化集合的错误引用

Oracle 升级后的 ORA-06531

为啥在 C# 10 中我会在初始化属性上收到编译器警告/错误 CS8618

为啥我会收到 ConcurrentModificationException?

为啥我会收到 CancelledKeyException?