2016-09-23 112 views
0

我写了下面的PL/SQL代码来生成报告。PL/SQL:数值或值错误:字符串缓冲区太小

CREATE OR REPLACE 

PACKAGE CAcxref AS 
    PROCEDURE CAcxref_PROC (inp_str  IN VARCHAR2,out_retCode OUT NUMBER,out_rec OUT VARCHAR2); 
END CAcxref; 
/
CREATE OR REPLACE 
PACKAGE BODY CAcxref AS 
OutArr  custom.ArrayType; 
V_PROCESS1 VARCHAR2(100); 
V_PROCESS2 VARCHAR2(100); 
V_PROCESS3 VARCHAR2(100); 
V_PROCESS4 VARCHAR2(100); 
v_CutOff VARCHAR2(100); 
TYPE RecTyp IS RECORD (
rec_PROCESS_NAME custom.c_master_notify_tbl.PROCESS_NAME%type, 
rec_SOL_ID custom.c_master_notify_tbl.SOL_ID%type, 
rec_schm_type custom.c_master_notify_tbl.SCHM_TYPE%type, 
rec_foracid custom.c_master_notify_tbl.FORACID%type, 
rec_RCRE_TIME custom.c_master_notify_tbl.RCRE_TIME%type); 
    TYPE Cacxref_data IS TABLE OF RecTyp 
    INDEX BY BINARY_INTEGER; 
    Cacxref_FetchData Cacxref_data; 

    lv_variable    VARCHAR2 (5000) := ''; 
    lv_cnt     NUMBER  ; 
CURSOR GetDetails (v_Process1 VARCHAR2,v_Process2 VARCHAR2,v_Process3 VARCHAR2,v_Process4 VARCHAR2,v_CutOff VARCHAR2) IS 

SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (V_Process1) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process2) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process3) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process4) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B'; 
PROCEDURE CAcxref_PROC(inp_str IN VARCHAR2, out_retCode OUT NUMBER, out_rec OUT VARCHAR2) 
IS 
BEGIN 
    out_retCode := 0; 
    out_rec := ''; 
    custom.stringToArray.formInputArr (inp_str,OutArr); 
    V_Process1 := OutArr(0); 
    DBMS_OUTPUT.PUT_LINE('Process one:'||V_Process1); 
    V_Process2 := OutArr(1); 
    DBMS_OUTPUT.PUT_LINE('Process two:'||V_Process2); 
    V_Process3 := OutArr(2); 
    DBMS_OUTPUT.PUT_LINE('Process THREE:'||V_Process3); 
    V_Process4 := OutArr(3); 
    DBMS_OUTPUT.PUT_LINE('Process four:'||V_Process4); 
    v_CutOff := OutArr(4); 
    DBMS_OUTPUT.PUT_LINE('Cutoff Time:'||v_CutOff); 
    IF NOT GetDetails%ISOPEN then 
     OPEN GetDetails(v_Process1,v_Process2,v_Process3,v_Process4,v_CutOff); 
     DBMS_OUTPUT.PUT_LINE('CUSRSOR HAS BEEN OPENED'); 
    END IF; 
DBMS_OUTPUT.PUT_LINE('COUNT IS:'||Cacxref_FetchData.COUNT); 

LOOP 
    FETCH GetDetails 
    BULK COLLECT 
    INTO Cacxref_FetchData 
    LIMIT 10; /* WARNING: NUMBER OF RECORDS FETCHED SHOULD MATCH SIZE OF OUTREC VARIABLE */ 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE BULK COLLECT LOOP'); 
    EXIT WHEN GetDetails%NOTFOUND; 
END LOOP; 

FOR indx in 1 .. Cacxref_FetchData.COUNT 
LOOP 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE FOR LOOP'); 
    lv_variable := Cacxref_FetchData(indx).rec_PROCESS_NAME || '|' || Cacxref_FetchData(indx).rec_SOL_ID || '|' || 
    Cacxref_FetchData(indx).rec_SCHM_TYPE || '|' || Cacxref_FetchData(indx).rec_FORACID||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||Cacxref_FetchData(indx).rec_RCRE_TIME ; 
    DBMS_OUTPUT.PUT_LINE('lv_cnt is 1 and lv_variable is:'||lv_variable); 
    out_rec := lv_variable; 
END LOOP; 
END CAcxref_PROC; 
END CAcxref; 
/
DROP PUBLIC SYNONYM CAcxref 
/
CREATE PUBLIC SYNONYM CAcxref FOR CAcxref 
/
Grant EXECUTE ON CAcxref TO TBAADM, TBAUTIL,TBAGEN,SYSTEM 
/
SET SERVEROUTPUT ON 
/

在执行我收到character string buffer too small错误是第一次,第二次虽然我没有得到任何错误,但没有行越来越光标获取无论是。

下面是我执行的截图:

Screenshot

我不能够理解为哪个变量被抛出此错误。

执行提示:

SQL> SET SERVEROUTPUT ON 
SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
BEGIN custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); END; 

* 
ERROR at line 1: 
ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at "CUSTOM.CACXREF", line 84 
ORA-06512: at line 1 


SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec); 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
COUNT IS:2 
INSIDE THE BULK COLLECT LOOP 

PL/SQL procedure successfully completed. 

SQL> print :out_rec 

OUT_REC 
-------------------------------- 

EDIT 我提出在PL/SQL一些变化,现在它是工作每个交替的时间,如果只有我设置具有大VARCHAR2值out_rec变量。

CREATE OR REPLACE 
PACKAGE CAcxref AS 
    PROCEDURE CAcxref_PROC (inp_str  IN VARCHAR2,out_retCode OUT NUMBER,out_rec OUT VARCHAR2); 
END CAcxref; 
/
CREATE OR REPLACE 
PACKAGE BODY CAcxref AS 
OutArr  tbaadm.basp0099.ArrayType; 
V_PROCESS1 VARCHAR2(20); 
V_PROCESS2 VARCHAR2(20); 
V_PROCESS3 VARCHAR2(20); 
V_PROCESS4 VARCHAR2(20); 
v_CutOff VARCHAR2(14); 
TYPE RecTyp IS RECORD (
rec_PROCESS_NAME custom.c_master_notify_tbl.PROCESS_NAME%type, 
rec_SOL_ID custom.c_master_notify_tbl.SOL_ID%type, 
rec_schm_type custom.c_master_notify_tbl.SCHM_TYPE%type, 
rec_foracid custom.c_master_notify_tbl.FORACID%type, 
rec_RCRE_TIME custom.c_master_notify_tbl.RCRE_TIME%type); 
    TYPE Cacxref_data IS TABLE OF RecTyp 
    INDEX BY BINARY_INTEGER; 
    Cacxref_FetchData Cacxref_data; 

    lv_variable    VARCHAR2 (3000) := ''; 
    lv_cnt     NUMBER  ; 
CURSOR GetDetails (v_Process1 VARCHAR2,v_Process2 VARCHAR2,v_Process3 VARCHAR2,v_Process4 VARCHAR2,v_CutOff VARCHAR2) IS 

SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (V_Process1) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process2) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process3) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B' 
UNION 
SELECT PROCESS_NAME,SOL_ID,SCHM_TYPE,FORACID,RCRE_TIME 
FROM custom.C_MASTER_NOTIFY_TBL 
WHERE PROCESS_NAME IN (v_Process4) 
AND TO_CHAR(RCRE_TIME,'DD-MM-YYYY HH24:MI:SS') <= TO_CHAR(TO_DATE('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
AND CXREF_STATUS IN ('O') AND DEL_FLG='N' AND ONLINE_OR_BATCH='B'; 
PROCEDURE CAcxref_PROC(inp_str IN VARCHAR2, out_retCode OUT NUMBER, out_rec OUT VARCHAR2) 
IS 
BEGIN 
    out_retCode := 0; 
    out_rec := ''; 
    tbaadm.basp0099.formInputArr (inp_str,OutArr); 
    V_Process1 := OutArr(0); 
    DBMS_OUTPUT.PUT_LINE('Process one:'||V_Process1); 
    V_Process2 := OutArr(1); 
    DBMS_OUTPUT.PUT_LINE('Process two:'||V_Process2); 
    V_Process3 := OutArr(2); 
    DBMS_OUTPUT.PUT_LINE('Process THREE:'||V_Process3); 
    V_Process4 := OutArr(3); 
    DBMS_OUTPUT.PUT_LINE('Process four:'||V_Process4); 
    v_CutOff := OutArr(4); 
    DBMS_OUTPUT.PUT_LINE('Cutoff Time:'||v_CutOff); 
    IF NOT GetDetails%ISOPEN then 
     OPEN GetDetails(v_Process1,v_Process2,v_Process3,v_Process4,v_CutOff); 
     DBMS_OUTPUT.PUT_LINE('CUSRSOR HAS BEEN OPENED'); 
    END IF; 
DBMS_OUTPUT.PUT_LINE('COUNT OF FETCHDATA IS:'||Cacxref_FetchData.COUNT); 

IF GetDetails%ISOPEN THEN 
--LOOP 
    FETCH GetDetails 
    BULK COLLECT 
    INTO Cacxref_FetchData 
    LIMIT 10; /* WARNING: NUMBER OF RECORDS FETCHED SHOULD MATCH SIZE OF OUTREC VARIABLE */ 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE BULK COLLECT LOOP'); 
       IF (Cacxref_FetchData.COUNT = 0) THEN 
        CLOSE GetDetails; 
        out_retcode := 1; 
        RETURN; 
       END IF; 
-- EXIT WHEN GetDetails%NOTFOUND; 
--END LOOP; 

FOR indx in 1 .. Cacxref_FetchData.COUNT 
LOOP 
    DBMS_OUTPUT.PUT_LINE('INSIDE THE FOR LOOP'); 
    lv_variable := Cacxref_FetchData(indx).rec_PROCESS_NAME || '|' || Cacxref_FetchData(indx).rec_SOL_ID || '|' || 
    Cacxref_FetchData(indx).rec_SCHM_TYPE || '|' || Cacxref_FetchData(indx).rec_FORACID||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' ||'|' 
    ||Cacxref_FetchData(indx).rec_RCRE_TIME ; 
    DBMS_OUTPUT.PUT_LINE('lv_cnt is 1 and lv_variable is:'||lv_variable); 
    out_rec := out_rec || lv_variable; 
        IF (indx = Cacxref_FetchData.COUNT) THEN 
         out_rec := out_rec || lv_variable;    

        ELSE 

         out_rec := out_rec || lv_variable || CHR (10);    

        END IF; 
END LOOP; 
RETURN; 
END IF; 
END CAcxref_PROC; 
END CAcxref; 
/
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAGEN; 
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAADM WITH GRANT OPTION; 
GRANT EXECUTE ON CUSTOM.CAcxref TO TBAUTIL; 

而现在的结果设定out_rec VARCHAR2(4000)后,看起来是这样的:使用

SQL> set serveroutput on 
SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT OF FETCHDATA IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACOPN|101|SBA|99101000116||||||||||||||||||||||12-APR-16 

PL/SQL procedure successfully completed. 

SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
COUNT OF FETCHDATA IS:2 
INSIDE THE BULK COLLECT LOOP 

PL/SQL procedure successfully completed. 

SQL> exec custom.CAcxref.CAcxref_Proc ('ACOPN!ACMOD!TEST!TEST1!12042016220000',:out_retCode,:out_rec) 
Process one:ACOPN 
Process two:ACMOD 
Process THREE:TEST 
Process four:TEST1 
Cutoff Time:12042016220000 
CUSRSOR HAS BEEN OPENED 
COUNT OF FETCHDATA IS:0 
INSIDE THE BULK COLLECT LOOP 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACMOD|102|SBA|99101000036||||||||||||||||||||||12-APR-16 
INSIDE THE FOR LOOP 
lv_cnt is 1 and lv_variable 
is:ACOPN|101|SBA|99101000116||||||||||||||||||||||12-APR-16 

PL/SQL procedure successfully completed. 
+0

也许您应该阅读“CUSTOM.CACXREF”第84行“ORA-06512:”的行。祝你好运。 –

+0

@BobJarvis,第84行是'CUSTOM \t CACXREF \t PACKAGE BODY “out_rec:= lv_variable; ”'from dba_source。但我无法理解out_rec怎么可能变小? – Mistu4u

+0

如何:out_rec定义? –

回答

1

(原“字符串缓冲区太小”的错误是由于SQL * Plus的绑定变量以捕获输出声明太小 - 这在评论中被清除了,下面的几点涉及代码给出交替运行结果的后续问题。)

我可以看到几个问题代码(除了未格式化,这使得它h以便发现错误 - 我建议整齐排列所有代码并用全局变量前缀g_,程序参数为p_,游标参数为cp_等)。

首先,光标getdetails是全局的(在包体层声明),但它永远不会关闭,所以我假设全局数组cacxref_fetchdata保留了会话剩余部分的第一个值。这是打算吗?

全局数组outarr让我有点困惑,因为它不是'out'参数,但似乎在解析inp_str的过程中使用。

有一个全局变量lv_cnt(为什么lv?)这是从来没有使用,但你有一个输出消息说'lv_cnt is 1'

v_cutoff作为游标参数传递,但不在游标中使用。

光标getdetails可以从四个union s内简化为:

cursor getdetails 
    (v_process1 varchar2 
    , v_process2 varchar2 
    , v_process3 varchar2 
    , v_process4 varchar2 
    ) -- not used: v_cutoff varchar2) 
is 
    select distinct process_name, sol_id, schm_type, foracid, rcre_time 
    from custom.c_master_notify_tbl 
    where process_name in (v_process1, v_process2, v_process3, v_process4) 
    and to_char(rcre_time,'DD-MM-YYYY HH24:MI:SS') 
      <= to_char(to_date('12042016220000','DDMMYYYY HH24:MI:SS'),'DD-MM-YYYY HH24:MI:SS') 
    and cxref_status = 'O' 
    and del_flg = 'N' 
    and online_or_batch = 'B'; 

日期看起来比较错误的,除非你想1-DEC-2016 00:00:00到 '前' 2-JAN-1997 23:59:59是。假设rcre_timedate,我认为你需要将其更改为:

and rcre_time <= to_date('12-04-2016 22:00:00','DD-MM-YYYY HH24:MI:SS') 

而且光标参数具有相同的名称为一些全局变量,这是混乱的,但编译器将使用的参数(我将前缀为了清楚起见,它们为cp_)。

批量读取循环看起来很奇怪 - 您一次读取10行,直到您点击一个%notfound,但您在最后一次读取之前不对数据执行任何操作。

loop 
    fetch getdetails bulk collect into cacxref_fetchdata limit 10; 
    /* warning: number of records fetched should match size of out_rec variable */ 
    dbms_output.put_line('inside the bulk collect loop'); 
    exit when getdetails%notfound; 
end loop; 

然后你遍历cacxref_fetchdata但你只使用最后一个(再次使用全局变量,这可能会影响后续调用)。

如果不通过调试器对表和数据运行它很难说,但是由于全局变量在过程调用之间保留了它们的值,并且您的光标只被获取了一次,所以我猜测一次运行的某个全局值会影响下一个的逻辑。我会整理代码,确保变量只有在必须是全局变量时才有效,并明确地重新初始化您不希望保留的任何内容。

相关问题