【问题标题】:Regexp_replace WITH DECIMAL is returning error ORA-01722 "Invalid Number"Regexp_replace WITH DECIMAL 返回错误 ORA-01722 "Invalid Number"
【发布时间】:2019-08-20 16:46:16
【问题描述】:

在 Oracle 中我有这个代码:

regexp_replace(DESCRIPTION_FIELD, '[^0-9.]+', '') 

效果很好,但现在我收到了错误:

ORA-01722“无效号码”。

删除小数可以解决这个问题,但会从返回值中删除小数。我猜最近添加了一些不良数据。解决方案?

【问题讨论】:

  • 我无法reproduce your issue in this db fiddle。如果您能展示一些实际产生问题的示例数据,那就太好了。
  • Oracle 数据库中的小数点分隔符是什么?
  • 这将是这样的:SELECT NVL(CAST(regexp_replace(DESCRIPTION_FIELD, '[^0-9.]+', '') AS NUMBER),0) FROM TABLE 返回 ORA -01722 错误。当我取出小数时,它运行良好。
  • 感谢您的帮助。我真正想要得到的是:使用可以包含任何数据的文本描述字段,如果它包含一个可以是金额的浮点数,请获取它。如果我们的描述总是有一个浮点数就好了,但它没有。没有“$”符号或逗号,因此需要通过查找格式为“一些数字,一个小数,然后是两个数字”的数字来找到它。谢谢!
  • 我不确定我们的小数分隔符是什么,抱歉。我是 58% 的 SQL 专家 :)

标签: sql regex oracle extract currency


【解决方案1】:

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]* 以确保不会发生这种情况。该组合包含在第二个分组中,使其成为可选的(后跟?) - 否则没有任何看起来像金钱的值会原封不动地传递,这可能也会出错。

【讨论】:

  • 先生,你是天才。
  • 这解决了我的问题。我用了你的“新”表达。这个逻辑就在我的脑海里,但是..那个漫长而疯狂的正则表达式正是我所需要的。谢谢亚历克斯!
  • @IdoIT4theMoney - 我意识到,如果没有潜在的货币价值,这将无济于事,如果有多个货币价值,则会给出奇怪的结果;更新以希望更全面。 (但正则表达式不是字符串点,所以很可能可以改进!)
  • 超级。再次感谢。这些也会有所帮助,因为我确实需要底片。我还有一个问题,如果它类似于“123.78TEST1234”,我只想要“123.78”部分。我相信您的正则表达式正在跳过并尝试返回 1234。(我的报告出错了,因为“1234”没有小数点并且 .xls 无法处理)。如何将其限制为仅获得“123.25”格式值的第一次出现?再次感谢!
【解决方案2】:

如果您会话的 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>;

【讨论】:

  • 感谢您的建议。我尝试以两种方式更改会话,仍然出现相同的错误。尝试了第三个和相同的错误。呃,我以为这真的会奏效!我充满希望。 (它返回了相同的 ORA-01722 错误。我们可能有几行数据包含错误的坏数据。可能在机器级别......??)
  • Try "select regexp_replace(DESCRIPTION_FIELD, '[^0-9.]+', '') from " 然后,这不能产生 ORA-01722... 我希望: )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-29
  • 2018-02-14
相关资源
最近更新 更多