TO_NUMBER invalid number error - sql

I have searched for and seen some similar questions, but none have solved my problem. I am getting a invalid number error on my TO_NUMBER in my where clause. Some things I have read said that it can be caused by where you place the TO_NUMBER in your where clause, so I was hoping someone could help me solve this. Here is the where clause in my query:
WHERE year_sec = TEST.YEAR_SEC_BY_DATE ('F', 0)
AND (year_sec = '2014F')
AND ((no_name LIKE '54%' AND user3 IS NOT NULL)
OR (SUBSTR (no_name, 1, 2) = '52' AND SUBSTR (no_name, 5, 1) = '8')
OR (no_name LIKE '56%'))
OR (TO_NUMBER(SUBSTR(year_sec,1,4), '9999') >= 2015)
AND ((no_name LIKE '543%' AND user3 IS NOT NULL)
OR (no_name LIKE '523%')
OR (no_name LIKE '563%'));
year_sec is always 4 digits with one letter after, and never null (if it isn't then there would be much bigger problems). So can anyone see why this would be causing the ORA-01722 error?
EDIT: Removed quotes, error while copying over sql.

Assuming that the error is coming from the to_number in your query and not, for example, from an invalid conversion in the year_sec_by_date function or somewhere else in your code, I would generally wager that Oracle is too dumb to lie to you. Somewhere in your data, you have at least one row where year_sec isn't a 4 digit number followed by a letter.
One way of finding the problem row would be to
CREATE OR REPLACE FUNCTION my_to_number( p_str IN VARCHAR2 )
RETURN NUMBER
IS
BEGIN
RETURN to_number( p_str );
EXCEPTION
WHEN others THEN
RETURN NULL;
END;
and then
SELECT year_sec, <<other columns>>
FROM <<your table>>
WHERE my_to_number( substr( year_sec, 1, 4 )) IS NULL
Note that if you have some rows where the year_sec is invalid that are being filtered out by other predicates in your query, there is no guarantee that Oracle will apply predicates in any particular order. Oracle may apply the to_number before or after any other predicate in the query.

The optimizer can rewrite your query and change where you expect the conversion to occur. Check for bad character data where you expect numeric data.
SELECT year_sec,
UPPER(SUBSTR(year_sec,1,4)) AS UPPER_YEAR,
LOWER(SUBSTR(year_sec,1,4)) AS LOWER_YEAR
FROM my_table
WHERE UPPER(SUBSTR(year_sec,1,4)) != LOWER(SUBSTR(year_sec,1,4))
From OraFAQ ORA-01722

Related

ORACLE - TO_NUMBER Function

I have column TEXT_INT in my table and I would like convert to DECIMAL using TO_NUMBER Function. Unfortunately I am getting
INVALID NUMBER ORA-722 error.
I doubt it may have characters in it. So Issued below query but there is no alphabets in TEXT_INT.
SELECT *
FROM NANTHA_TABLE
WHERE UPPER(TEXT_INT) != LOWER(TEXT_INT);
Would you please provide an idea to resolve this issue or ways to finding wrong data?
try this:
create function like this:
CREATE OR REPLACE function f_invalid_number(number_field in varchar2) return number as
n_d number;
begin
n_d := TO_number(number_field);
return 0;
exception
when others then
return 1;
end;
/
then you can check invalid data like this:
SELECT *
FROM NANTHA_TABLE
WHERE f_invalid_number(TEXT_INT) =1
This query may help you.
select your_wrong_col ,
case
when trim(TRANSLATE(your_wrong_col ,'0123456789','')) is null
then 'numeric'
else 'not_numeric'
end as your_wrong_col
from YOUR_TABLE
where trim(TRANSLATE(your_wrong_col ,'0123456789','')) is not null;
Finds non-numeric rows.
Please use below query to find records where TEXT_INT column has characters other than number.
select * from NANTHA_TABLE where NOT REGEXP_LIKE(TEXT_INT,'^[0-9]+$')
In case you are expecting more string symbols in your column which should be considered as valid you can include them in the NOT REGEXP_LIKE condition so those columns also don't appear in the query.
eg. If expecting a '-' symbol in the start of the string for some values:
NOT REGEXP_LIKE(COLUMN_NAME, '^-?[0-9.]+$') "
where
'^' Begining
'?' Zero or One occurance
'+' One of More occurance
'$' End of String
Please note i know that the decimals in my above query will be accepted even if counted twice. For that I propose a different solution to count the number of decimals in the string and throw error. If any1 can integrate it with the REGEXP you are most welcome. How to count number of decimals for check.
LENGTH(COLUMN_NAME) - LENGTH(REPLACE(COLUMN_NAME,'.','')) > 1
To find more details about the REGEXP_LIKE please use the following link.

converted data type (varchar) still shows conversion error

I have a column that can store text but is used to store a number (I did not make the system!) someone has put a blank value in (i.e. not content but not null) and its causing error: -
Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to numeric.
I have reduced the issue down to the below: -
SELECT
T1.[FIELD_5],
ISNUMERIC(T1.[FIELD_5]),
NULLIF(T1.[FIELD_5],''),
ISNULL(NULLIF(T1.[FIELD_5],''),0),
CONVERT(DECIMAL(18,5),ISNULL(NULLIF(T1.[FIELD_5],''),0))
FROM
[MyTBL] T1
ORDER BY
ISNUMERIC(T1.[FIELD_5])
The issue data is in [FIELD_5]
I can see SQL sees a value as not numeric
I can see that NULLIF is successfully changing it to a NULL value
I can see the ISNULL is turning the NULLIF result to 0
But the CONVERT on the ISNULL result results in the error message, I would expect it to result in 0.00000
Use try_convert():
SELECT T1.[FIELD_5], ISNUMERIC(T1.[FIELD_5]), NULLIF(T1.[FIELD_5], ''),
COALESCE(NULLIF(T1.[FIELD_5], ''), 0),
TRY_CONVERT(DECIMAL(18, 5), COALESCE(NULLIF(T1.[FIELD_5], ''), 0))
FROM [MyTBL] T1
ORDER BY ISNUMERIC(T1.[FIELD_5]);
try_convert() was introduced in SQL Server 2012. If you are using an earlier version, then you need to use a case expression.
(I switched ISNULL() to COALESCE() because I prefer to use ANSI standard functions where practical.)
There is some non numeric value available you can do that check with case as below:
select convert(decimal(18,5), '')
Throws error as "Error converting data type varchar to numeric.
"
SELECT
T1.[FIELD_5],
ISNUMERIC(T1.[FIELD_5]),
NULLIF(T1.[FIELD_5],''),
ISNULL(NULLIF(T1.[FIELD_5],''),0),
CONVERT(DECIMAL(18,5), iif(isnumeric(ISNULL(T1.[FIELD_5]),'0') > 1,T1.[FIELD_5],'0')
ISNULL(NULLIF(T1.[FIELD_5],''),0))
FROM
[MyTBL] T1
ORDER BY
ISNUMERIC(T1.[FIELD_5])
This was a case of better investigation was needed, I should have realised as in my opinion SQL doesn't lie its normally always user error.
I run it again without the order by clause and then selected the row that would have shown up after the last row that did show up (i.e. that row that caused the error).
[FIELD_5] contained the value 1E-07, an infamous bad import from Excel!
What doesn't add up is why when I had the order by ISNUMERIC on, I did not see this value at the top of the list, only the blank values that were indeed being managed properly.
Question solved, I should have stuck investigating but I think this is worth leaving up to help other investigate in the future.

Error on query with "Replace"

I Have an error on a oracle server but I don't understand why is not work.
I use the software oracle sql developer.
The query is:
SELECT * FROM TestView WHERE REPLACE(TestView.Row2, '.', ',') > 0 ;
The value who is in TestVue.Row2 : '46.08','-46.47','1084.05','66500',...
"TestView" is a view who check to return a row without empty value
When I Execute the query I have always an error who says:
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause:
*Action:
Thanks for your help
Zoners
You have a row in your table, which cannot be parsed into number format. Most likely it is a blank column.
SELECT * FROM TestVue WHERE TestVue.Row2 IS NULL ;
Use a NVL Function to avoid errors caused by null field and a TO_NUMBER function to cast into a number before comparision with zero
SELECT * FROM TestView WHERE TO_NUMBER(REPLACE(NVL(TestView.Row2,'0'), '.', ',')) > 0 ;
You should be able to find the row with something like:
select Row2
from TestVuw
where length(trim(translate(Row2, '+-.,0123456789', ' '))) = 0
Of course, this allows multiple +, -, ., and ,. It can be further refined using a regular expression, but this usually works to find the bad ones.

ORACLE - Select Count on a Subquery

I've got an Oracle table that holds a set of ranges (RangeA and RangeB). These columns are varchar as they can hold both numeric and alphanumeric values, like the following example:
ID|RangeA|RangeB
1 | 10 | 20
2 | 21 | 30
3 | AB50 | AB70
4 | AB80 | AB90
I need to to do a query that returns only the records that have numeric values, and perform a Count on that query. So far I've tried doing this with two different queries without any luck:
Query 1:
SELECT COUNT(*) FROM (
SELECT RangeA, RangeB FROM table R
WHERE upper(R.RangeA) = lower(R.RangeA)
) A
WHERE TO_NUMBER(A.RangeA) <= 10
Query 2:
WITH A(RangeA,RangeB) AS(
SELECT RangeA, RangeB FROM table
WHERE upper(RangeA) = lower(RangeA)
)
SELECT COUNT(*) FROM A WHERE TO_NUMBER(A.RangeA) <= 10
The subquery is working fine as I'm getting the two records that have only numeric values, but the COUNT part of the query is failing. I should be getting only 1 on the count, but instead I'm getting the following error:
ORA-01722: invalid number
01722. 00000 - "invalid number"
What am I doing wrong? Any help is much appreciated.
You can test each column with a regular expression to determine if it is a valid number:
SELECT COUNT(1)
FROM table_of_ranges
WHERE CASE WHEN REGEXP_LIKE( RangeA, '^-?\d+(\.\d*)?$' )
THEN TO_NUMBER( RangeA )
ELSE NULL END
< 10
AND REGEXP_LIKE( RangeB, '^-?\d+(\.\d*)?$' );
Another alternative is to use a user-defined function:
CREATE OR REPLACE FUNCTION test_Number (
str VARCHAR2
) RETURN NUMBER DETERMINISTIC
AS
invalid_number EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_number, -6502);
BEGIN
RETURN TO_NUMBER( str );
EXCEPTION
WHEN invalid_number THEN
RETURN NULL;
END test_Number;
/
Then you can do:
SELECT COUNT(*)
FROM table_of_ranges
WHERE test_number( RangeA ) <= 10
AND test_number( RangeB ) IS NOT NULL;
Try this query:
SELECT COUNT(*)
FROM table R
WHERE translate(R.RangeA, 'x0123456789', 'x') = 'x' and
translate(R.RangeB, 'x0123456789', 'x') = 'x'
First, you don't need the subquery for this purpose. Second, using to_number() or upper()/lower() are prone to other problems. The function translate() replaces each character in the second argument with values from the third argument. In this case, it removes numbers. If nothing is left over, then the original value was an integer.
You can do more sophisticated checks for negative values and floating point numbers, but the example in the question seemed to be about positive integer values.
Coming to this question almost four years later (obviously, pointed here from a much newer thread). The other answers show how to achieve the desired output, but do not answer the OP's question, which was "what am I doing wrong?"
You are not doing anything wrong. Oracle is doing something wrong. It is "pushing" the predicate (the WHERE condition) from the outer query into the inner query. Pushing predicates is one of the most basic ways in which the Optimizer makes queries more efficient, but in some cases (and the question you ask is a PERFECT illustration) the result is not, in fact, logically equivalent to the original query.
There are ways to prevent the Optimizer from pushing predicates; or you can write the query in a better way (as shown in the other answers). But if you wanted to know why you saw what you saw, this is why.

Converting data type varchar to numeric

Msg 8114, Level 16, State 5, Procedure spGetDetails, Line 88
Error converting data type varchar to numeric.
I have already converted this #mfr_id to int type then also getting the above error.
I'm getting error while executing stored procedure.
The line which I'm getting error is:
if(#mfr_id = 5)
Use:
if(#mfr_id = '5')
Value comparisons have to be the same data type, or there has to be implicit data type conversion. Explicit conversion -- which is when you use CAST/CONVERT -- is ideal for maintenance because the operation is obvious.
Depending on your needs, the ISNUMERIC function might help. And be careful to define a length to your [n]varchar variables.
Updated answer
So it seems that #mfr_id is a varchar. To avoid the syntactic issue use the answer in OMG Ponies post.
But you also say that it is storing the string "1 2, 3, 4.....". So semantically are you wanting the IF statement to be true if it contains the value '5'?
If so you might need something like this
set #mfr_id = REPLACE(#mfr_id, ' ','')
if ((#mfr_id LIKE '5,%') OR (#mfr_id LIKE '%,5,%') OR (#mfr_id LIKE '%,5'))
Original Answer - Obsolete
if(CONVERT(int, #mfr_id) = 5)
should do the trick hopefully. See http://msdn.microsoft.com/en-us/library/ms187928.aspx for details. Although actually I think it should be implicitly converted. What is the value of #mfr_id? It should tell you this in the error message I think.
This answer is written using Oracle's PL/SQL syntax and one of the Oracle regular expression routines. I don't know T-SQL well enough to transcribe it but I expect that similar capabilities are available:
FOR aRow IN
(WITH DATA AS (SELECT #mfg_id AS S FROM DUAL)
SELECT REGEXP_SUBSTR(S, '[^ ,]+', 1, LEVEL) AS NUM_STRING
FROM DATA
CONNECT BY LEVEL < LENGTH(S) - LENGTH(REGEXP_REPLACE(S, '[ ,]', '')))
LOOP
IF aRow.NUM_STRING = '5' THEN
NULL; -- do something appropriate here
END IF;
END LOOP;
Share and enjoy.