问题
I would like to convert a string column to number, with ability to handle exceptions, such as text, in Oracle SQL.
The target is to convert text to 0, and number in string format into number.
Example Input:
ID Column1
1 01A
2 02A
3 1.30
4 1,30
5 100000
6 (Note: 1 empty space)
7 (Note: Null)
Expected output
ID Column1
1 0
2 0
3 1.3
4 1.3
5 100000
6 0
7 0
I tried the following SQL command:
select ID, to_number(Column1) As Column1
from Table1
The error code is ORA-01722 if there is any non-numeric output.
The expected result is to get rid of error ORA-01722, even when input has null, space, text (i.e. anything non-numeric)
回答1:
This requires two measures:
- Check if there are any non-numeric characters (see this solution)
You could use regex functions instead ofTRANSLATE
but I expect them to be slower. - Convert to number, accepting both ',' and '.' as decimal markers (see this solution)
Query:
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;
Results:
COLUMN1 RESULT
-------- ----------
'01A' 0
'02A' 0
'1.30' 1.3
'1,30' 1.3
'100000' 100000
' ' 0
'' 0
回答2:
In order to cast a column to number, we will need to eliminate/replace the text we can use a case statement with regex to achieve this.
Please try running this
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
Logic by regexp look for anything that's not like a number change it to 0 if its a number cast as number , trim and nvl is to handle space and null.
Note : replace ',' to '.' is to handle 1,3 = 1.2 , but this is bound to fail if there are multiple comma's in the column (we can write a more complex logic to check the comma count , but seems unnecessary ) , ideally 1,3 should be denoted as text and made 0
Hope this helps
回答3:
You can achieve this using the following query:
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
Cheers!!
回答4:
You can use regexp_like()
and case
logic:
SELECT (CASE WHEN REGEXP_LIKE(column1, '[0-9]*[.,]+[0-9]+')
THEN REPLACE(column1, ',', '.')
ELSE '0'
END)
FROM test_data;
This is rather careful about handling edge cases:
- Only one
.
/,
is allowed. - If there is a decimal point, then there needs to be a digit afterwards (this can be adjusted).
Here is a db<>fiddle. It adds an additional test case of just '.'
.
来源:https://stackoverflow.com/questions/57884039/oracle-sql-convert-string-to-number-with-exceptions-to-treat-text-as-0