SELECT TO_NUMBER('*') FROM DUAL
これは明らかに例外を私に与えます:
ORA-01722:番号が無効です
それを「スキップ」して、代わりに0
またはNULL
を取得する方法はありますか?
全体の問題:私はNVARCHAR2
フィールドを持っていますが、これには数字が含まれ、ほとんど;-)がありません(*
など)、列から最大の数字を選択する必要があります。
はい、私はそれがひどいデザインであることを知っていますが、これは私が今必要なものです...:-S
[〜#〜] upd [〜#〜]:
私は自分でこの問題を解決しました
COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+')), 0)
私はこれ以上良いものを見つけることができませんでした:
function safe_to_number(p varchar2) return number is
v number;
begin
v := to_number(p);
return v;
exception when others then return 0;
end;
COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+(\.\d+)?')), 0)
また、スケール> 0(小数点の右側の数字)の数値を取得します。
Oracle Database 12c Release 2
から、TO_NUMBERとDEFAULT ... ON CONVERSION ERROR
を使用できます。
SELECT TO_NUMBER('*' DEFAULT 0 ON CONVERSION ERROR) AS "Value"
FROM DUAL;
またはCAST
:
SELECT CAST('*' AS NUMBER DEFAULT 0 ON CONVERSION ERROR) AS "Value"
FROM DUAL;
select COALESCE(TO_NUMBER(REGEXP_SUBSTR( field, '^(-|+)?\d+(\.|,)?(\d+)?$')), 0) from dual;
123を12に変換しますが、123aまたは12a3to .
元の質問とかなり古いskoolのフィッティング
select a, decode(trim(translate(b,'0123456789.',' ')),null,to_number(b),0) from
(
select '1' a, 'not a number' b from dual
union
select '2' a, '1234' b from dual
)
おそらく、独自の正規表現を使って数値をテストするのは少し面倒ですが、以下のコードは機能する可能性があります。組み込みのOracle機能を使用しているため、ユーザー定義関数を含むGabeによる他のソリューションはより堅牢であると思います(そして私の正規表現はおそらく100%正確ではありません)が、行く価値があるかもしれません:
with my_sample_data as (
select '12345' as mynum from dual union all
select '54-3' as mynum from dual union all
select '123.4567' as mynum from dual union all
select '.34567' as mynum from dual union all
select '-0.3462' as mynum from dual union all
select '0.34.62' as mynum from dual union all
select '1243.64' as mynum from dual
)
select
mynum,
case when regexp_like(mynum, '^-?\d+(\.\d+)?$')
then to_number(mynum) end as is_num
from my_sample_data
これにより、次の出力が得られます。
MYNUM IS_NUM
-------- ----------
12345 12345
54-3
123.4567 123.4567
.34567
-0.3462 -0.3462
0.34.62
1243.64 1243.64
select DECODE(trim(TRANSLATE(replace(replace(A, ' '), ',', '.'), '0123456789.-', ' ')),
null,
DECODE(INSTR(replace(replace(A, ' '), ',', '.'), '.', INSTR(replace(replace(A, ' '), ',', '.'), '.') + 1),
0,
DECODE(INSTR(replace(replace(A, ' '), ',', '.'), '-', 2),
0,
TO_NUMBER(replace(replace(A, ' '), ',', '.'))))) A
from (select '-1.1' A from DUAL union all select '-1-1' A from DUAL union all select ',1' A from DUAL union all select '1..1' A from DUAL) A;
このコードは、-1-1、1..1、12-2などの文字列を除外します。また、ここでは正規表現を使用していません。
最善の方法が機能ソリューションのようですが、もしあなたが苦労している環境で必要な特権を持っていなければ(私のように)、これを試すことができます:
SELECT
CASE
WHEN
INSTR(TRANSLATE('123O0',
' qwertyuıopğüasdfghjklşizxcvbnmöçQWERTYUIOPĞÜASDFGHJKLŞİZXCVBNMÖÇ~*\/(){}&%^#$<>;@€|:_=',
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
),
'X') > 0
THEN 'Y'
ELSE 'N'
END is_nonnumeric
FROM DUAL
ところで:私の場合、問題は「、」と「。」が原因でした。 :)それを考慮に入れてください。 this one からインスピレーションを受けています。また、 これ はより簡潔に見えます。
ちなみに:親愛なるオラクル、このような小さいが非常に貴重なニーズのために、いくつかの組み込み関数を作成してください。
以前のソリューション(@sOliverと@Mike Meyersから)の組み合わせと、REGEXPから最後の「$」を削除して、できるだけ多くの数字を取得しようとします。
構成テーブルから実際の番号をフィルタリングするために使用でき、「12日」として番号の横に「親切な」コメントを付けることができます。
with my_sample_data as ( select '12345' as mynum from dual union all select '123.4567' as mynum from dual union all select '-0.3462' as mynum from dual union all select '.34567' as mynum from dual union all select '-.1234' as mynum from dual union all select '**' as mynum from dual union all select '0.34.62' as mynum from dual union all select '24Days' as mynum from dual union all select '42ab' as mynum from dual union all select '54-3' as mynum from dual ) SELECT mynum, COALESCE( TO_NUMBER( REGEXP_SUBSTR( mynum, '^(-|+)?\d*(.|,)?(\d+)?') ) , 0) is_num FROM my_sample_data;
与えるだろう
MYNUM IS_NUM
-------- ----------
12345 12345
123.4567 123.4567
-0.3462 -0.3462
.34567 0.34567
-.1234 -0.1234
** 0
0.34.62 0.34
24Days 24
42ab 42
54-3 54