NLS_NUMERIC_CHARACTERS setting for decimal - oracle

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!

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.

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;

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.

Best way is,
SELECT to_number(replace(:Str,',','')/100) --into num2
FROM dual;

Related

Convert string to decimal Oracle database

I intended convert data type string to decimal in Oracle data base and i get this error:
ORA-01722: número no válido 01722. 00000 - "invalid number" *Cause:
The specified number was invalid. *Action: Specify a valid number
Code:
TO_NUMBER('5.0') AS numero
CAST('5.0' AS NUMBER) AS numero
select TO_NUMBER('5.0') from dual;
select NLS_NUMERIC_CHARACTERS
from v$nls_parameters;
--There must be '.' in value filed to run above query
The code you have posted works fine for me.
However, check you NLS/locale settings. If I change mine to use something other that '.' as the decimal separator then I get the same error.
So it would appear that it may be down to your locale settings. You can check with select * from v$nls_parameters to see what the nls_numeric_characters is set to.
thanks for your answeres, it served as a guide to find the root of the problem. verifying the local configuration of nls_numeric_characters encontre ',.'
Apparently the server configuration is different and therefore caused the error in the Query.
To give solution, replace '.' by ',' I assumed the configuration of nls_numeric_characters on the server is with ','.
select TO_NUMBER(REPLACE('5.0','.',',')) from dual;

Saving Persian/Arabic Digits and Numbers inside Oracle Database

We have an Oracle Database which has many records in it. Recently we noticed that we can not save Persian/Arabic digits within a column with a datatype nvarchar2 and instead of the numbers it shows question marks "?".
I went through this to check the charset using these commands :
SELECT *
from NLS_DATABASE_PARAMETERS
WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
and this command
SELECT USERENV('language') FROM DUAL;
The results are these two respectively:
I also issue this command :
SELECT DUMP(myColumn, 1016) FROM myTable;
And the result is like this :
Typ=1 Len=22 CharacterSet=AL16UTF16: 6,33,6,44,6,27,6,45,0,20,0,3f,0,3f,0,2f,0,3f,0,2f,0,3f
The results seem to be okay but unfortunately we still cannot save any Persian/Arabic digit within that column. however the Persian/Arabic alphabets are okay. Do you know what is the cause of this problem ?
Thank You
USERENV('language') does not return your client characters set.
So, SELECT USERENV('language') FROM DUAL; is equal to
SELECT l.value||'_'||t.value||'.'||c.value
FROM (SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_LANGUAGE') l
CROSS JOIN (SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_TERRITORY') t
CROSS JOIN (SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET') c;
It is not possible to get the client NLS_LANG by any SQL statement (although there seems to be a quirky workaround: How do I check the NLS_LANG of the client?)
Check your client NLS_LANG setting. It is defined either by Registry (HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG, resp. HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG) or as Environment variable. The Environment variable takes precedence.
Then you must ensure that your client application (you did not tell us which one you are using) uses the same character set as specified in NLS_LANG.
In case your application runs on Java have a look at this: Database JDBC Developer's Guide - Globalization Support
See also OdbcConnection returning Chinese Characters as "?"
Do yourself a favor and convert the main character set of your database from AR8MSWIN1256 to AL32UTF8. Most of these problems will simply go away. You can forget about NCHAR and NVARCHAR2. They are not needed anymore.
It's a one-time effort that will pay back a thounsand times.
See Character Set Migration for instructions.

Why Does Oracle 10g to_char(date time) Truncate Strings?

I got a bug report where Oracle 10g was truncating return values from to_char(datetime):
SQL> select to_char(systimestamp, '"day:"DD"hello"') from dual;
TO_CHAR(SYSTIMESTAMP,'"DAY:"DD"HE
---------------------------------
day:27hel
Notably, this does not appear to happen in Oracle 11g. My question is, why does it happen at all? Is there some configuration variable to set to tell to_char(datetime) to allocate a bigger buffer for its return value?
I'm not sure but it might be just displaying in SQL*Plus. Have you tried to run it in Toad? Or if you assign result to varchar2 in PL/SQL block and output result?
Here what I've found in SQL*Plus Reference for 10g:
The default width and format of unformatted DATE columns in SQL*Plus
is determined by the database NLS_DATE_FORMAT parameter. Otherwise,
the default format width is A9. See the FORMAT clause of the COLUMN
command for more information on formatting DATE columns.
Your values is trimmed to 9 characters which corresponds to default A9 format. I don't have same version and this behaviour is not reproducing in 11g so can you please check my theory?
I've got the same problem and I know the solution.
I use Release 11.2.0.4.0 but I beleave it is possible to repeat the situation in other versions. It somehow depends on client. (E.g. I cannot repeat it using SQL*Plus, only with PL/SQL Devepoper)
Try this:
select to_char(systimestamp, '"day:"DD"йцукенг OR any other UTF-encoded-something"') from dual
union all
select to_char(systimestamp, '"day:"DD"hello"') from dual;
You'll get the following result:
day:08йцукенг OR any other UTF-encoded-so
day:08hello
You can see the "mething" is lost. This is exactly 7 bytes exceeded because of 7 two-byte simbols "йцукенг". Oracle allocates buffer for the number of characters, not a number of required bytes.
The command
alter session set nls_length_semantics=byte/char
unfortunately does not affect this behavior.
So my solution is to cast a result as varchar2(enough_capacity)
select cast(to_char(systimestamp, '"day:"DD"йцукенг OR any other UTF-encoded-something"') as varchar(1000)) from dual
union all
select to_char(systimestamp, '"day:"DD"hello"') from dual
Explicit typecasting makes expression independent from client or configuration.
BTW, the same thing happens in all implicit to_char-conversions. E.g.
case [numeric_expression]
when 1 then '[unicode_containing_string]'
end
Result might be cutted.

NLS_NUMERIC_CHARACTERS reset when accessed from weblogic datasource

I have problem with certain code and the root cause turned out to be NLS_NUMERIC_CHARACTERS setting at session level.
when I run the query directly on database:
SQL> select 'nls_database_parameters' , p.* from nls_database_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS'
2 union all
3 select 'nls_session_parameters', p.* from nls_session_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS'
4 union all
5 select 'nls_instance_parameters', p.* from nls_instance_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS';
'NLS_DATABASE_PARAMETERS' PARAMETER VALUE
------------------------- ------------------------ -----
nls_database_parameters NLS_NUMERIC_CHARACTERS .,
nls_session_parameters NLS_NUMERIC_CHARACTERS .,
nls_instance_parameters NLS_NUMERIC_CHARACTERS .,
But, when I run this same query from weblogic datasource
select 'nls_database_parameters' , p.* from nls_database_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS'
union all
select 'nls_session_parameters', p.* from nls_session_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS'
union all
select 'nls_instance_parameters', p.* from nls_instance_parameters p where PARAMETER = 'NLS_NUMERIC_CHARACTERS';
-- 'NLS_DATABASE_PARAMETERS', PARAMETER, VALUE
1 nls_database_parameters NLS_NUMERIC_CHARACTERS .,
2 nls_session_parameters NLS_NUMERIC_CHARACTERS ,
3 nls_instance_parameters NLS_NUMERIC_CHARACTERS .,
The session value is wrong and is being reset by some trigger/script when accessed through weblogic datasource, I checked the weblogic startup scripts etc to see if we reset somewhere but no help.
Any pointers/ideas in this direction much appreciated if somebody faced similar issue.
I'm not familiar with the Weblogic side of things, but you can scoop up material from within Oracle by searching its source code objects (triggers, procedures, packages, functions) in DBA_SOURCE. It may contain "execute immediate" statements (or the equivalent DBMS_SQL dynamic SQL call) with something similar to:
alter session set nls_numeric_characters = ',.';
Or it could also be calling DBMS_SESSION.SET_NLS procedure:
dbms_session.set_nls('NLS_NUMERIC_CHARACTERS', '".,"');
Querying it as follows should point you to some suspects (and likely some false positives too). You can improve it by filtering by owner.
SELECT *
FROM dba_source s
WHERE (upper(s.text) LIKE '%SET\_NLS%' ESCAPE '\'
OR upper(s.text) LIKE '%NLS\_NUMERIC\_CHARACTERS%' ESCAPE '\')
AND owner != 'SYS';
The dynamic view V$SQL may have your command there if it's an anonymous PL/SQL block or script.
SELECT *
FROM v$sql s
WHERE (upper(s.sql_fulltext) LIKE '%SET\_NLS%' ESCAPE '\'
OR upper(s.sql_fulltext) LIKE '%NLS\_NUMERIC\_CHARACTERS%' ESCAPE '\')
AND s.parsing_schema_name = 'YOUR_DB_USER';
If you have already spotted the code that is causing the error and it's under control you could also fix the conversion by doing it explicitly in to_number (or to_char) with the syntax below:
SQL> select to_number('1.5', '999999D999', 'NLS_NUMERIC_CHARACTERS=,.'),
2 to_number('1.5', '999999D999', 'NLS_NUMERIC_CHARACTERS=.,')
3 from dual;
TO_NUMBER('1.5','999999D999',' TO_NUMBER('1.5','999999D999','
------------------------------ ------------------------------
15 1,5
This way you become nls session immune to it, but it may not be feasible to fix all your code to use this.
It is unlikely that this is being set explicitly. I'd wager that it is being set implicitly as a result of the user.language and user.country values used to initialize your JVM. I don't know exactly how WebLogic gets these by default but I would guess that the server's locale is set to one where the comma is the decimal separator.
You should be able to override the default WebLogic settings by setting the language and country in the startWebLogic script
set JAVA_OPTIONS=%JAVA_OPTIONS% -Duser.language=en -Duser.country=US
Of course, that may have impact other things as well (the language of error messages for example).

Ssrs on Oracle date parameter

I am using SSRS 2005 to run against a Oracle data source. I used this simple query
SELECT order_number FROM apps.oe_order_headers_all
WHERE ordered_date >= :start
AND ordered_date < :end + 1
and rownum = 1
Firstly I got:
ORA-01745: invalid host/bind variable name
I ignore the error and click refresh (to let SSRS determine the columns returned and parameters used)
SSRS prompts me for the values of the parameters, I tried 01/01/2014, 01-JAN-2014, 01-01-2014 for both parameters but all got this error:
Cannot bind type System.String as Blob. (System.Data.OracleClient)
The order_number is NUNBER and ordered_date is DATE in oracle.
Not sure it's a pl sql thing or SSRS thing?
Not sure if the second error is just a follow-up to the initial one, but the first error is because start is a reserved word in Oracle; you'll get an ORA-01745 from this in SQL*Plus or SQL Developer too:
SQL> var start varchar2(10);
SQL> select :start from dual;
select :start from dual
*
ERROR at line 1:
ORA-01745: invalid host/bind variable name
end is allowed though. If you change the bind variable name to, say, :start_date - and add the explicit to_date(:start_date, 'YYYY-MM-DD') and to_date(:end_date, 'YYYY-MM-DD') that OracleUser suggested so you know what format to enter the variables in - that will go away.
I can only imagine that will resolve the second error too, which I guess is coming from the parameter being in an odd state at that point.

Resources