66
SELECT TO_NUMBER('*') FROM DUAL

这显然给了我一个例外:

ORA-01722: 无效号码

有没有办法“跳过”它并获取0NULL代替?

整个问题:我有NVARCHAR2字段,其中包含数字而不是几乎 ;-) (如*),我需要从列中选择最大的数字。

是的,我知道这是一个糟糕的设计,但这就是我现在需要的...... :-S

更新

对于我自己,我已经解决了这个问题

COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+')), 0)
4

9 回答 9

44

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;

db<>小提琴演示

于 2017-08-25T17:32:41.217 回答
30
COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+(\.\d+)?')), 0) 

还将获得比例 > 0 的数字(小数点右侧的数字)。

于 2013-04-26T21:18:49.020 回答
15

我找不到比这更好的东西了:

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;
于 2010-12-20T04:56:32.377 回答
12
select COALESCE(TO_NUMBER(REGEXP_SUBSTR( field, '^(-|+)?\d+(\.|,)?(\d+)?$')), 0) from dual;

它将 123 转换123 但将123a12a3 转换0

于 2014-06-25T03:44:50.217 回答
7

适合原始问题和相当古老的问题

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
)
于 2010-12-20T17:11:59.137 回答
1

滚动你自己的正则表达式来测试一个数字可能有点混乱,但下面的代码可能会起作用。我认为 Gabe 涉及用户定义函数的另一个解决方案更强大,因为您使用的是内置的 Oracle 功能(我的正则表达式可能不是 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
于 2010-12-20T16:22:37.007 回答
1
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 等。而且我在这里没有使用正则表达式。

于 2014-09-03T06:42:14.743 回答
0

以前的解决方案(来自@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                                      
于 2018-02-21T15:19:48.303 回答
0

最好的方法似乎是功能解决方案,但如果您在苦苦挣扎的环境中没有必要的特权(如我),那么您可以尝试这个:

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

顺便说一句:在我的情况下,问题是由于“,”和“。” :) 所以考虑到这一点。受此启发。而且这个看起来更简洁。

顺便说一句 2:亲爱的 Oracle,您能否为这些小而宝贵的需求创建一些内置函数?

于 2018-03-09T20:48:24.107 回答