Oracle SQL将字符串转换为数字,但例外情况是将文本视为0

9rnv2umw  于 2023-08-04  发布在  Oracle
关注(0)|答案(6)|浏览(261)

我想将字符串列转换为数字,并能够在Oracle SQL中处理异常,例如文本。
目标是将文本转换为0,并将字符串格式的数字转换为数字。
输入示例:

ID   Column1
1    01A
2    02A
3    1.30
4    1,30
5    100000
6           (Note: 1 empty space)
7           (Note: Null)

字符串
预期产量

ID   Column1
1    0
2    0
3    1.3
4    1.3
5    100000
6    0
7    0


我尝试了以下SQL命令:

select ID, to_number(Column1) As Column1 
from Table1


如果有任何非数字输出,则错误代码为ORA-01722。
预期的结果是消 debugging 误ORA-01722,即使输入为空、空格、文本(即任何非数字)

0kjbasz6

0kjbasz61#

这需要采取两项措施:
1.检查是否有任何非数字字符(参见solution
你可以使用regex函数代替TRANSLATE,但我希望它们会更慢。
1.转换为数字,接受','和'.'作为小数点标记(参见solution
查询:

WITH test_data AS
(
  SELECT '01A' AS column1 FROM dual UNION ALL
  SELECT '02A' AS column1 FROM dual UNION ALL
  SELECT '1.30' AS column1 FROM dual UNION ALL
  SELECT '1,30' AS column1 FROM dual UNION ALL
  SELECT '100000' AS column1 FROM dual UNION ALL
  SELECT ' ' AS column1 FROM dual UNION ALL
  SELECT NULL AS column1 FROM dual
)
SELECT
    '''' || column1 || '''' AS column1, -- only to show result, distinct between '' and ' '
    -- Check if there are only numeric characters
    CASE WHEN TRIM( TRANSLATE( column1, '0123456789-,.', ' ') ) IS NULL
      THEN
          NVL(  -- replace NULL by 0
              TO_NUMBER(
                  -- both ',' and '.' should work as decimal marker so replace
                  REPLACE( TRIM( column1 ), ',', '.' ),
                  -- second parameter necessary to allow third
                  '99999999999999999999D99999999999999999999',
                  -- do not rely on NLS settings, use '.' as decimal marker
                  'NLS_NUMERIC_CHARACTERS=''. '''
              ),
          0 )
      ELSE 0  -- default value if not numeric
    END AS result
FROM test_data;

字符串
结果如下:

COLUMN1      RESULT
-------- ----------
'01A'             0
'02A'             0
'1.30'          1.3
'1,30'          1.3
'100000'     100000
' '               0
''                0

epggiuax

epggiuax2#

您可以使用validate_conversion()函数,而无需任何正则表达式。

创建数据表

create table table1
(
    id      number generated as identity
    column1 varchar2(50),
)
/

INSERT INTO TABLE1 (COLUMN1) VALUES ('01A');
INSERT INTO TABLE1 (COLUMN1) VALUES ('02A');
INSERT INTO TABLE1 (COLUMN1) VALUES ('1.30');
INSERT INTO TABLE1 (COLUMN1) VALUES ('1,30');
INSERT INTO TABLE1 (COLUMN1) VALUES ('100000');
INSERT INTO TABLE1 (COLUMN1) VALUES (' ');
INSERT INTO TABLE1 (COLUMN1) VALUES (null);

字符串

进行转换

select
    column1 as original_value,
    validate_conversion(replace(column1, ',', '.') as number, '999990D00', 'NLS_NUMERIC_CHARACTERS = ''.,''') as is_the_value_convertable,
    case 
        when validate_conversion(replace(column1, ',', '.') as number, '999990D00', 'NLS_NUMERIC_CHARACTERS = ''.,''') = 1
        then nvl(cast(replace(column1, ',', '.') as number, '999990D00', 'NLS_NUMERIC_CHARACTERS = ''.,'''), 0)
        else 0 
        end as converted_value
from
    table1;


使用适合您的用例的适当NLS参数和数字格式。
注意:前两列只是为了清楚起见,您可以省略它们。第二列显示验证函数的工作方式。当可以无错误地转换值时输出1,否则输出0(而不是错误)。第三列是执行实际的转换,使用验证函数来确定是应该尝试转换,还是只输出0。它被 Package 在nvl()中,因为否则输入null将返回null,而不是在无法转换的情况下所需的0
文件:https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/VALIDATE_CONVERSION.html#GUID-DC485EEB-CB6D-42EF-97AA-4487884CB2CD

mzmfm0qo

mzmfm0qo3#

为了将列转换为数字,我们需要删除/替换文本,我们可以使用正则表达式的case语句来实现这一点。
请尝试运行此

Select ID ,
      CASE 
         WHEN NOT regexp_like (   NVL ( trim (replace(column1 , ',' ,'.')) , 0 )  ,         
                '^[0-9]+[\.0-9]*$'     )   
         THEN 0
        ELSE  TO_NUMBER ( NVL ( trim (replace(column1 , ',' ,'.')) , 0 ) )
      END column1
    from table1

字符串
逻辑通过regexp查找任何不像数字的东西,如果它是一个数字转换为数字,则将其更改为0,trim和nvl将处理空格和null。
注意:将','替换为'.'是为了处理1,3 = 1.2,但是如果列中有多个逗号,这肯定会失败(我们可以编写一个更复杂的逻辑来检查逗号计数,但似乎没有必要),理想情况下1,3应该表示为文本并为0
希望这对你有帮助

flmtquvp

flmtquvp4#

您可以使用以下查询来实现这一点:

alter session set NLS_NUMERIC_CHARACTERS = '.,';
SELECT
    YOUR_COLUMN,
    CASE
        WHEN REGEXP_COUNT(YOUR_COLUMN, '[A-Za-z]') > 0 OR TRIM(YOUR_COLUMN) IS NULL THEN 0
        ELSE TO_NUMBER(REPLACE(YOUR_COLUMN, ',', '.'))
    END AS MY_NUMBER
FROM
    YOUR_TABLE

字符串
db<>fiddle demo
干杯!

b0zn9rqh

b0zn9rqh5#

您可以使用regexp_like()case逻辑:

SELECT (CASE WHEN REGEXP_LIKE(column1, '[0-9]*[.,]+[0-9]+')
             THEN REPLACE(column1, ',', '.')
             ELSE '0'
        END)
FROM test_data;

字符串
这对于处理边缘情况是相当小心的:

  • 只允许一个./,
  • 如果有小数点,则后面需要有一个数字(这可以调整)。

Here是一个db<>fiddle。它添加了一个额外的测试用例,只有'.'

6yjfywim

6yjfywim6#

select ID, to_number(Column1 DEFAULT 0 ON CONVERSION ERROR) As Column1 from Table1

字符串
根据这份Oracle文件

相关问题