24

I have one db setup in a test machine and second in production machine. When I run:

select to_number('100,12') from dual 

Then it gives error in test machine. However, this statement works quite fine in production machine.

Now, when I check for NLS_NUMERIC_CHARACTERS then I see ',' (comma) in both machine. Is there anywhere else I should be looking for the decimal setting?

Cheers!

user272735
  • 10,473
  • 9
  • 65
  • 96
Jaanna
  • 1,620
  • 9
  • 26
  • 46

4 Answers4

52

You can see your current session settings by querying nls_session_parameters:

select value
from nls_session_parameters
where parameter = 'NLS_NUMERIC_CHARACTERS';

VALUE                                  
----------------------------------------
.,                                       

That may differ from the database defaults, which you can see in nls_database_parameters.

In this session your query errors:

select to_number('100,12') from dual;

Error report -
SQL Error: ORA-01722: invalid number
01722. 00000 -  "invalid number"

I could alter my session, either directly with alter session or by ensuring my client is configured in a way that leads to the setting the string needs (it may be inherited from a operating system or Java locale, for example):

alter session set NLS_NUMERIC_CHARACTERS = ',.';
select to_number('100,12') from dual;

TO_NUMBER('100,12')
-------------------
             100,12 

In SQL Developer you can set your preferred value in Tool->Preferences->Database->NLS.

But I can also override that session setting as part of the query, with the optional third nlsparam parameter to to_number(); though that makes the optional second fmt parameter necessary as well, so you'd need to be able pick a suitable format:

alter session set NLS_NUMERIC_CHARACTERS = '.,';
select to_number('100,12', '99999D99', 'NLS_NUMERIC_CHARACTERS='',.''')
from dual;

TO_NUMBER('100,12','99999D99','NLS_NUMERIC_CHARACTERS='',.''')
--------------------------------------------------------------
                                                        100.12 

By default the result is still displayed with my session settings, so the decimal separator is still a period.

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • 1
    Thanks. Apparently the problem was with client software. I was using oracle developer in one machine while PL/SQL developer in another. – Jaanna Jul 07 '14 at 13:07
  • Is it possible to add "DEFAULT -1 ON CONVERSION ERROR" into your very last select query when using to_number? It causes an Oracle error ORA-43918 in my case. – gouessej Sep 02 '21 at 08:46
  • 1
    @gouessej - it wasn't when I wrote this answer *8-) But [yes, it is](https://dbfiddle.uk/?rdbms=oracle_18&fiddle=91283443f9c364d61d0563e8ece43690). Maybe you're seeing [this](https://stackoverflow.com/a/66037721/266304)? – Alex Poole Sep 02 '21 at 09:10
  • Thank you for your answer. Your example works when the first parameter is a literal but not when it's a column name. I've just tried with Oracle 19. The hint doesn't help. – gouessej Sep 02 '21 at 10:52
  • [It does work with a column](https://dbfiddle.uk/?rdbms=oracle_18&fiddle=826c0ede0b6cb3796095184369452fe3) - so not sure what's different for you. (That hint might only apply for 12c; but then it should work without it in later versions). It might be worth asking a new question with a [mcve]. – Alex Poole Sep 02 '21 at 11:14
  • Ok I found the problem. It works as expected in a simple example but when I add this part into a more complicated select query, it fails, Oracle seems to lose the information of a parameter type. I wrote a reproducer yesterday, I'll post it somewhere Monday. I simplified the query a lot, it allowed me to work around the problem but I still think that the original query should have worked as is. By the way, the reproducer is self-contained and the pseudo-table contains only one line. – gouessej Sep 03 '21 at 20:17
  • @AlexPoole Maybe you'd like to give it a look: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=af484b133e845837c2d550bfcf6bdd2c I get an error "ORA-43918: This argument must be a literal" :s – gouessej Sep 07 '21 at 10:35
  • It's interesting, and you could ask a new question about it; but it looks like a bug so you'd probably be better off raising an SR with Oracle. – Alex Poole Sep 07 '21 at 10:56
3

Jaanna, the session parameters in Oracle SQL Developer are dependent on your client computer, while the NLS parameters on PL/SQL is from server.

For example the NLS_NUMERIC_CHARACTERS on client computer can be ',.' while it's '.,' on server.

So when you run script from PL/SQL and Oracle SQL Developer the decimal separator can be completely different for the same script, unless you alter session with your expected NLS_NUMERIC_CHARACTERS in the script.

One way to easily test your session parameter is to do:

select to_number(5/2) from dual;
pringi
  • 3,987
  • 5
  • 35
  • 45
Jonas
  • 39
  • 1
0

To know SESSION decimal separator, you can use following SQL command:

ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ', ';

select SUBSTR(value,1,1) as "SEPARATOR"
      ,'using NLS-PARAMETER' as "Explanation"
  from nls_session_parameters
  where parameter = 'NLS_NUMERIC_CHARACTERS'

UNION ALL

select SUBSTR(0.5,1,1) as "SEPARATOR" 
      ,'using NUMBER IMPLICIT CASTING' as "Explanation"
  from DUAL;

The first SELECT command find NLS Parameter defined in NLS_SESSION_PARAMETERS table. The decimal separator is the first character of the returned value.

The second SELECT command convert IMPLICITELY the 0.5 rational number into a String using (by default) NLS_NUMERIC_CHARACTERS defined at session level.

The both command return same value.

I have already tested the same SQL command in PL/SQL script and this is always the same value COMMA or POINT that is displayed. Decimal Separator displayed in PL/SQL script is equal to what is displayed in SQL.

To test what I say, I have used following SQL commands:

ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ', ';

select 'DECIMAL-SEPARATOR on CLIENT: (' || TO_CHAR(.5,) || ')' from dual;

DECLARE
    S VARCHAR2(10) := '?';
BEGIN

    select .5 INTO S from dual;

    DBMS_OUTPUT.PUT_LINE('DECIMAL-SEPARATOR in PL/SQL: (' || S || ')');
END;
/

The shorter command to know decimal separator is:

SELECT .5 FROM DUAL;

That return 0,5 if decimal separator is a COMMA and 0.5 if decimal separator is a POINT.

schlebe
  • 3,387
  • 5
  • 37
  • 50
0

Best way is,

SELECT to_number(replace(:Str,',','')/100) --into num2 
FROM dual;
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Pramod
  • 1
  • When using code in a question, please put all code into code blocks: usually, indent all code lines by 4 spaces, or surround the code block with 3 backticks (`\`\`\``). For inline code on the same line as non-code, surround the code with a single backtick on each side (`\``). – CertainPerformance Apr 08 '19 at 09:28