2011-08-09 17 views
0

私は10、10aなどのようにvarchar2としてハウスナンバーを含むテーブルを持っています。 '10a'のような数値ではないすべての行を検出したいと思います。 私の解決策は、 '10a'のようなデータを数値に変換しようとすると例外を起こすすべての行を出力することです。
to_number()で例外が発生する行を特定する

declare 
number_correct number; 
number_incorrect varchar2(4000); 
begin 
for rec in(select '10' house_nr from dual union select '10a' house_nr from dual) 
loop 
number_correct:=to_number(rec.house_nr); 
number_incorrect:=rec.house_nr; 
end loop; 
exception 
when others then 
dbms_output.put_line('correct: '||number_correct); 
dbms_output.put_line('incorrect: '||number_incorrect); 
end; 

それは間違っては10Aですが、そうでないことを示す必要があります。

答えて

4

あなたが尋ねた実際の質問については、@Daveが正しいのですが、達成しようとしていることは、あなたがやっていることとは異なると思います。書かれているように、PL/SQLブロックは値が最初の非番号になるまで評価します。あなたはすべての値が評価されたい場合は、このようなものが必要です:ループ内に例外処理を移動させることで

BEGIN 
    FOR rec IN (SELECT '10' house_nr FROM DUAL 
       UNION ALL 
       SELECT '10a' house_nr FROM DUAL 
       UNION ALL 
       SELECT '11' house_nr FROM DUAL) LOOP 
     error_fl   := FALSE; 
     BEGIN 
     number_correct := TO_NUMBER(rec.house_nr); 
     EXCEPTION 
     WHEN VALUE_ERROR THEN 
      error_fl := TRUE; 
     WHEN OTHERS THEN 
      RAISE; 
     END; 

     IF error_fl THEN 
     DBMS_OUTPUT.put_line('incorrect: ' || rec.house_nr); 
     ELSE 
     DBMS_OUTPUT.put_line('correct: ' || rec.house_nr); 
     END IF; 
    END LOOP; 
END; 

をエラーが発生した後、我々は処理を継続することができます。また、このバージョンでは、予期しないエラーではなく、実際に発生したエラーが変換エラーである場合にのみ、「間違った」メッセージが返されます。このような特定の条件に対してエラー処理を記述するときは、できるだけ正確にすることが重要です。


@Stephenが指摘するように、正規表現は、一般に、PL/SQLプロシージャまたは関数よりも高速であり、単一のSQLステートメントは、典型的には、手続きのループよりも優れています。しかし、正規表現の機能はwhere句でのみ使用することができますので、あなたはすべての値の結果を確認したい場合は、二回あなたのテーブルを照会する必要があるだろう:

WITH test_num as (SELECT '10' house_nr FROM DUAL 
        UNION ALL 
        SELECT '10a' house_nr FROM DUAL 
        UNION ALL 
        SELECT '11' house_nr FROM DUAL) 
SELECT 'correct' AS status, a.* 
FROM test_num a 
WHERE REGEXP_LIKE(t1, '[^[:digit:]]') 
UNION ALL 
SELECT 'incorrect', a.* 
FROM test_num a 
WHERE NOT REGEXP_LIKE(t1, '[^[:digit:]]'); 

あなたが正規表現に慣れていない場合、またはこれは、ほとんどの状況で正規表現を使用したほど速くはありません

CREATE OR REPLACE FUNCTION is_num(p_string VARCHAR2) 
    RETURN NUMBER 
    DETERMINISTIC IS 
    v_test  NUMBER; 
BEGIN 
    v_test := p_string; 
    RETURN 1; 
EXCEPTION 
    WHEN VALUE_ERROR THEN 
     RETURN 0; 
    WHEN OTHERS THEN 
     RAISE; 
END; 

WITH test_num as (SELECT '10' house_nr FROM DUAL 
        UNION ALL 
        SELECT '10a' house_nr FROM DUAL 
        UNION ALL 
        SELECT '11' house_nr FROM DUAL) 
SELECT CASE is_num(t1) WHEN 0 THEN 'correct' ELSE 'incorrect' END AS status, a.* 
FROM test_num a; 

、しかし:あなたはまだ独自の関数を作成することによって、単一のSQL文でこれを行うことができ、適当な発現を思い付くことができません関数ベースのインデックスはregexp関数については細心の注意を払っていますが、このような関数には問題はありません。この特定のクエリのインデックスが必要なようには思えませんが、それは何かを覚えておいてください。

+0

あなたは正しいです。私はすべての価値を評価したい。 – reforrer

1

、正規表現を使用してみてください。例:

select * 
from 
(
    select '10a' a from dual 
    union all 
    select '10' a from dual 
) where regexp_like(a, '[^[:digit:]]'); 
+0

有効な数値文字列には、数字以外の文字を含めることができます。 –

+0

@Dave Costa - 私は同意します...しかし、おそらく住所にはありません(つまり、ピリオドやネガティブではない) – Randy

+0

住宅番号は?私はおそらく期間のキャラクターがあるかもしれないと思うが、ネガティブハウスナンバーはあまり意味がない。でも、まだ問題は、行ごとのplsql処理に頼る代わりに、正規表現を使って解決できると思うでしょう。 –

2

スワップの2行の順序:最初の行が例外をスローあなたがそれらを持っているため、と

number_correct:=to_number(rec.house_nr); 
number_incorrect:=rec.house_nr; 

、 2番目の行はスキップされているので、ループの前回の反復からの「間違った」値が報告されています(これは定義上、正常に完了したため実際には間違っていません)。

私はまたto_number()呼び出しが例外をスローした場合、number_correctへの割り当ては発生しませんので、それは例外ハンドラでその値を出力する無意味なようで、定義によると

dbms_output.put_line('correct: '||number_correct); 

行を削除します。

関連する問題