PL / SQL:数字或值错误:字符串缓冲区太小

时间:2016-09-23 15:16:45

标签: oracle plsql

我编写了以下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
--------------------------------

修改 我在PL / SQL中进行了一些更改,现在只要我将out_rec变量设置为大的varchar2值,它就会每隔一段时间工作。

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.

1 个答案:

答案 0 :(得分:1)

(原始的'字符串缓冲区太小'错误是由于用于捕获声明的输出的SQL * Plus绑定变量太小 - 这在评论中被清除。以下几点与后续行动有关关于代码在备用运行中给出结果的问题。)

我可以看到代码中的一些问题(除了未格式化,这使得很难发现错误 - 我建议整齐地列出所有代码并使用$(document).ready(function () { $("input[name=logintype]").change(function(){ if($("#rdiogoogle").is(':checked')){ $("#btgoogle").show(); $("#btnerp").hide(); }else if($("#rdioerp").is(':checked')){ $("#btngoogle").hide(); $("btnerp").show(); } }); }); 为全局变量添加前缀,过程参数为{{1 ,g_等游标参数。)

首先,游标p_是全局的(在包体层声明),但它永远不会关闭,所以我认为全局数组cp_保留了其余会话的第一个值。这是有意的吗?

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

有一个从未使用的全局变量outarr(为什么inp_str?),但您有一条输出消息lv_cnt

lv作为游标参数传递,但未在游标中使用。

光标'lv_cnt is 1'可以从四个v_cutoff简化为:

getdetails

日期比较看起来不对,除非您希望unioncursor 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:002-JAN-1997 23:59:59,我认为您需要将其更改为:

rcre_time

此外,游标参数与某些全局变量具有相同的名称,这很令人困惑,尽管编译器将使用这些参数(为了清楚起见,我会在它们前面添加date。)

批量提取循环看起来很奇怪 - 您一次获取10行,直到您点击and rcre_time <= to_date('12-04-2016 22:00:00','DD-MM-YYYY HH24:MI:SS') ,但在最后一次提取之前您不对数据执行任何操作。

cp_

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

如果不通过调试器运行表和数据,很难判断,但由于全局变量在过程调用之间保留其值,并且光标仅被提取一次,我猜测一次运行中的某些全局值会影响下一个逻辑。我会整理代码,确保变量只有绝对必须是全局的,并明确地重新初始化你不想保留的任何东西。