Skip to Main Content
  • Questions
  • to_char(number_value) throws ORA-01722: invalid number

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Ken.

Asked: December 09, 2016 - 8:54 pm UTC

Last updated: December 11, 2016 - 3:50 am UTC

Version: 11.2

Viewed 1000+ times

You Asked

I was working on a customer's database (now 11.2, but it has been upgraded/migrated a handful of times since the 90's). As part of the current project, we are quering data for transformation into a new application schema. The query contains to_char(number_value) and for the oldest data, it would return the ORA-01722 error. As we added rownum filters to the where clause we managed to find a row that triggers it. The value was nominally 0.03 (there is another VARCHAR2 column that stores the string value the user typed into the application) The number value had about 40 decimal places

text_value=0.03
number_value=.030000000000000005828670879282071837224

Clearly those ending decimals are insignificant.

Observed an odd behavior in SQL*Plus 11.2 on a record that throws the ORA error, just querying number_value would not display the value at all, even with numwidth set to 40. A GUI tool used by the DBA would display it. I tried the dump function and it showed values, so I knew there were values physically in the db.

We corrected the data by applying a rounding using length(mod(number_value,1)) >20 (update <the table> set number_value = round(number_value, 20) where length(mod(number_value,1)) >=20). A quick way to scale the rounding to the magnitude. Then the to_char in the original query didn't throw the error anymore.

I've always known that Oracle stores numbers to 38 digits of precision. But it appeared that some were higher than that.

looking for some history from past Oracle versions regarding physical number storage (NUMBER with no scale or precision specified in column definition) to understand the nature of these particular records. I wasn't sure what to look at in the dump function to perhaps identify a storage issue (or at least something that would make to_char act up).

and Connor said...

digits of precision is not the same as digits.

You have 21 bytes (1 exponent, 20 mantissa) and in this case, we could hold all the data in that 21 bytes

SQL> create table t ( x number );

Table created.

SQL>
SQL> insert into t values (.030000000000000005828670879282071837224 );

1 row created.

SQL>
SQL> col x format 999.999999999999999999999999999999999999999999999
SQL> set lines 160
SQL> col d format a80
SQL> select x, dump(x) d from t;

                                                 X D
-------------------------------------------------- --------------------------------------------------------------------
    .030000000000000005828670879282071837224000000 Typ=2 Len=21: 192,4,1,1,1,1,1,1,1,6,83,87,71,88,93,83,8,19,38,23,41

1 row selected.


Can you elaborate on how you are getting the error ? I'm not seeing that

SQL> select to_char(x) from t;

TO_CHAR(X)
----------------------------------------
.030000000000000005828670879282071837224

1 row selected.


Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

KJM, December 11, 2016 - 1:39 pm UTC

If I had access to the customer data, I could run the dump function and compare.

Your to_char and test case corresponds. I was hoping there might be something for what might trigger Invalid Number.

I will return to the site early in 2017. Perhaps I can run the statement again with the dump function and collect a spool file.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library