PlSql翻译功能问题

时间:2011-07-14 18:56:23

标签: oracle plsql oracle11g ora-01722 ora-06502

我已经创建了一个游标来选择实际数据,然后循环输出原始值和转换为数字后的值。该应用程序偶尔会抛出无效的数字错误。下面是我的测试(不包括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);

这是输出:

Raw answer: 4
As number: 4
Raw answer: 3
As number: 3
Raw answer: 1.00
As number: 1
Raw answer: <3

我收到:

  

PL / SQL:数字或值错误:字符到数字转换错误

...当Raw回答是'&lt; 3'时。

请注意,应用程序使用的实际代码如下所示:

AND TO_NUMBER(REPLACE(TRANSLATE ( decode( INSTR(hra_ans.answer_text, '.',1 , 2), 0 , UPPER(hra_ans.answer_text) , 0),'ABCDEFGHIJKLMNOPQURSTWVXYZ+<>:',' '), ' ','')) 

并且是动态sql字符串中where子句的一部分。我用case语句替换了decode语句因为我得到了一个函数或伪列'DECODE'可能只在SQL语句中使用错误。

最后,我的问题是:

  1. 为什么翻译功能不能替换小于号和
  2. ORA-1722和ORA-06502错误之间有什么区别(以外行人的名义)?
  3. 编辑:当我将case语句更改为:

    时,我注意到了
    CASE v_instr 
                                                     WHEN 0 THEN UPPER(v_answer)
                                                     ELSE '0'
    

    我不再收到06502错误。通过查看我发布的原始代码行,是否有任何关于可能导致无效数字错误的建议(假设没有考虑到要翻译的字符串中不存在字符)?或者,有没有更好的方法来完成原始开发人员试图做的事情?

    以下是变量声明:

    v_answer varchar2(2000);
    v_number number;
    v_instr number;
    

1 个答案:

答案 0 :(得分:5)

首先,TRANSLATE不会替换'&lt;'符号,因为它没有机会。 CASE语句正在评估一个条件中的数字和另一个条件中的字符。如果CASE的输出是一致的,我相信你的错误就会消失:

  v_number := TO_NUMBER(REPLACE(TRANSLATE (CASE TO_CHAR(v_instr) 
                                             WHEN '0' THEN UPPER(v_answer)
                                             ELSE '0' 
                                           END,'ABCDEFGHIJKLMNOPQURSTWVXYZ+<>:',' '), ' ',''));

来自this post on asktom.com

  

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;