在Oracle中我有这个代码:
regexp_replace(DESCRIPTION_FIELD, '[^0-9.]+', '')
工作正常,但现在我收到错误:
ORA-01722“无效编号”。
删除小数会修复此问题,但会从返回值中删除小数。我猜最近有一些不好的数据。解决方案?
regexp_replace()
没有产生那个错误;问题是当您将替换的结果转换为数字时。例如,对于原始值XYZ2626...266.88
,您的模式会带回2626...266.88
,而to_number('2626...266.88')
会抛出ORA-01722。
通过查找格式为“某些数字,小数,然后是两个数字”的数字
你可以寻找它,而不是试图排除其他字符:
with your_table (description_field) as (
select 'No money value' from dual
union all
select 'Some sensible 98765.43 value' from dual
union all
select '01234-1234545 54.00' from dual
union all
select 'XYZ2626...266.88' from dual
union all
select 'ABC-123.45XYZ' from dual
union all
select 'ABC123.45XYZ6.78' from dual
)
select description_field,
regexp_replace(DESCRIPTION_FIELD, '[^0-9.]+', '') as original,
regexp_replace(DESCRIPTION_FIELD, '.*?((-?\d+\.\d{2})[^0-9]*)?$', '\2') as new
from your_table;
DESCRIPTION_FIELD ORIGINAL NEW
---------------------------- -------------------- --------------------
No money value
Some sensible 98765.43 value 98765.43 98765.43
01234-1234545 54.00 01234123454554.00 54.00
XYZ2626...266.88 2626...266.88 266.88
ABC-123.45XYZ 123.45 -123.45
ABC123.45XYZ6.78 123.456.78 6.78
我允许使用负数,但你可能不想要那些......如果有多个潜在的货币价值,那么最后一个也是如此。
捕获组(-?\d+\.\d{2})
查找可选的减号,后跟任意数量的数字,后跟一个句点,后跟正好2个数字。但这本身并不会阻止其后的数字,所以接下来是[^0-9]*
以确保不会发生。该组合被包含在第二个分组中以允许它是可选的(后面是?
) - 否则没有看起来像金额的任何值的值都会不加改变地传递,这也可能是错误的。
如果会话的NLS_NUMERIC_CHARACTERS具有错误的小数点设置,则通常会发生此错误。
您可以使用以下命令更改会话的设置:
alter session set NLS_NUMERIC_CHARACTERS = '.,';
要么
alter session set NLS_NUMERIC_CHARACTERS = ',.';
这将仅为您当前的会话设置小数和组分隔符。
或者在select语句中有一个更通用的解决方案,它总是假设'。'作为表中数据的小数点。并将显示您的会话的小数点数。
select to_number(regexp_replace(ESCRIPTION_FIELD, '[^0-9.]+', ''), '999999999999.99999', 'NLS_NUMERIC_CHARACTERS = ''.,''') from <your table>;
编辑
如果在字符串中找到更多的小数点,并且您可以接受跳过某些小数点,则可能会有效。
select to_number(regexp_substr(regexp_replace(ESCRIPTION_FIELD, '[^0-9.]+', ''),'([0-9]*.[0-9]*)'), '999999999999.99999', 'NLS_NUMERIC_CHARACTERS = ''.,''') from <your table>;