3

実際のデータを選択するためのカーソルを作成し、それをループして、生の値と数値に変換された後の値を出力します。アプリケーションが無効な数値エラーをスローすることがあります。以下は私のテスト(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:数値または値のエラー:文字から数値への変換エラー

...生の答えが「<3」の場合。

アプリケーションで使用される実際のコードは次のようになっていることに注意してください。

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

動的SQL文字列のwhere句の一部です。関数または疑似列「DECODE」がSQLステートメントのみのエラー内で使用される可能性があるため、decodeステートメントをcaseステートメントに置き換えました。

最後に、私の質問は次のとおりです。

  1. 変換関数がより小さい記号を置き換えないのはなぜですか
  2. ORA-1722エラーとORA-06502エラーの違いは(素人の言葉で)何ですか?

編集:caseステートメントを次のように変更すると気づきました:

CASE v_instr 
                                                 WHEN 0 THEN UPPER(v_answer)
                                                 ELSE '0'

06502エラーが発生しなくなりました。私が投稿した元のコード行を見て、無効な数値エラーの原因について何か提案はありますか(翻訳される文字列に文字が存在しないと仮定して)?または、元の開発者がやろうとしていたことを達成するためのより良い方法はありますか?

変数宣言は次のとおりです。

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

1 に答える 1

5

まず、TRANSLATE は「<」記号を置き換えていません。チャンスがないからです。CASE ステートメントは、一方の条件では数値に評価され、もう一方の条件では char に評価されます。CASE の出力に一貫性がある場合、エラーは解消されると思います。

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

asktom.com のこの投稿から:

ORA-1722 は無効な番号です。文字列を数値に明示的または暗黙的に変換しようとしましたが、失敗しています。

これは、さまざまな理由で発生する可能性があります。これは通常、SQL でのみ (クエリ中に) 発生し、plsql では発生しません (plsql はこのエラーに対して別の例外をスローします)。

編集:

regexp_replace の使用は良さそうですが、これをコーディングする場合は、読みやすいと思うので、DECODE の代わりに CASE を使用します。

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;
于 2011-07-14T19:53:05.810 に答える