Mat*_*t M 3 oracle plsql oracle11g ora-06502 ora-01722
我创建了一个光标来选择实际数据,然后循环输出原始值和转换为数字后的值.该应用程序偶尔会抛出无效的数字错误.下面是我的测试(不包括select语句)代码和输出.
LOOP
FETCH myCursor into v_answer;
EXIT WHEN myCursor%notfound;
DBMS_OUTPUT.PUT_LINE('Raw answer: ' || v_answer );
v_instr := INSTR(v_answer, '.',1 , 2) ;
v_number := TO_NUMBER(REPLACE(TRANSLATE (CASE v_instr
WHEN 0 THEN UPPER(v_answer)
ELSE 0
END,'ABCDEFGHIJKLMNOPQURSTWVXYZ+<>:',' '), ' ',''));
DBMS_output.put_line('As number: ' || v_number);
Run Code Online (Sandbox Code Playgroud)
这是输出:
Raw answer: 4
As number: 4
Raw answer: 3
As number: 3
Raw answer: 1.00
As number: 1
Raw answer: <3
Run Code Online (Sandbox Code Playgroud)
我收到:
PL/SQL:数字或值错误:字符到数字转换错误
......当Raw回答为"<3"时.
请注意,应用程序使用的实际代码如下所示:
AND TO_NUMBER(REPLACE(TRANSLATE ( decode( INSTR(hra_ans.answer_text, '.',1 , 2), 0 , UPPER(hra_ans.answer_text) , 0),'ABCDEFGHIJKLMNOPQURSTWVXYZ+<>:',' '), ' ',''))
Run Code Online (Sandbox Code Playgroud)
并且是动态sql字符串中where子句的一部分.我用case语句替换了decode语句因为我得到了一个函数或伪列'DECODE'可能只在SQL语句中使用错误.
最后,我的问题是:
编辑:我注意到当我将case语句更改为:
CASE v_instr
WHEN 0 THEN UPPER(v_answer)
ELSE '0'
Run Code Online (Sandbox Code Playgroud)
,
我不再收到06502错误.通过查看我发布的原始代码行,是否有任何关于可能导致无效数字错误的建议(假设没有考虑到要翻译的字符串中不存在字符)?或者,有没有更好的方法来完成原始开发人员试图做的事情?
以下是变量声明:
v_answer varchar2(2000);
v_number number;
v_instr number;
Run Code Online (Sandbox Code Playgroud)
首先,TRANSLATE不会替换'<'符号,因为它没有机会.CASE语句正在评估一个条件中的数字和另一个条件中的字符.如果CASE的输出是一致的,我相信你的错误会消失:
v_number := TO_NUMBER(REPLACE(TRANSLATE (CASE TO_CHAR(v_instr)
WHEN '0' THEN UPPER(v_answer)
ELSE '0'
END,'ABCDEFGHIJKLMNOPQURSTWVXYZ+<>:',' '), ' ',''));
Run Code Online (Sandbox Code Playgroud)
ORA-1722是无效的号码.我们试图明确或隐含地将字符串转换为数字,但它失败了.
这可能由于多种原因而发生.它通常仅在SQL中(在查询期间)不在plsql中发生(plsql为此错误引发了不同的异常).
编辑:
你对regexp_replace的使用看起来不错,但是如果我编码这个,我会使用CASE而不是DECODE,因为我觉得它更容易阅读:
v_number := CASE WHEN INSTR(v_answer, '.',1 , 2) = 0 THEN -- has 0 or 1 period
TO_NUMER(REGEXP_REPLACE(v_answer,'[^0-9.]',''))
ELSE 0 -- has more than one period
END;
Run Code Online (Sandbox Code Playgroud)