Saving Persian/Arabic Digits and Numbers inside Oracle Database - oracle

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.

Related

PL/SQL Developer - last character is missing in the results grid

We have a table with a column name A with type nvarchar(23).
following query will always return 23 which means that the actual length of all records are 23.
select length(trim(req.A)), count(*)
from tableName req
group by length(trim(req.A));
|length(trim(req.A))|count(*)|
------------------------------
|23 |1006 |
But when we select from this table with following query it behaves different and it seems that the last character is always removed in result Gridview in PL/SQL Developer.
select LENGTHB(req.A) lenb, length(req.A) len, req.* from tableName req
where req.A = 'NHBBBBB1398052635902235'; -- Note to the equal sign and the last charactar (5) of the where clause
the result is:
|lenb|len| A |
---------------------------------
|46 |23 |NHBBBBB139805263590223|
As you can see the last character (5) is removed in the select result.
Also when we rewrite previous query with to_char() it works fine & return correct result with the length of 23 and (5) as the last character.
select LENGTHB(req.A) lenb, length(req.A) len, to_char(req.A) from tableName req
where req.A = 'NHBBBBB1398052635902235';
the result is:
|lenb|len| to_char(req.A) |
----------------------------------
|46 |23 |NHBBBBB1398052635902235|
Can you please explain whats happen!? Is this related to PL/SQL Developer configs? How to solve this?
I believe that is a bug caused by the different character sets of oracle db you'r connected on and the client you executed that query on.
Some character sets is a mutibyte like 'AL32UTF8' character set which can use multiple bytes to store one character.
so you could check the character set of your db using:
select * from nls_database_parameters where parameter like '%SET%';
and try setting NLS_LANG character set to the character set used by your client application and try again.
hope that helps.
It seems that the problem was an old version of PL/SQL Developer which our customers used. When they updated to the newer version, the problem has been solved.

sql*plus is truncating the columns names according to the values in that columns

I have two broad questions:
Q1. Are executing the lines of code in Oracle SQL Developer and executing the same code in sqlplus command prompt same things?
(reason I ask this that I heard that not all the sqlplus commands are executable in SQL Developer. If answer to above question is yes then please then few useful links will help).
Q2. I am spooling the results of a sql query to a .csv file, but the thing is that columns names are truncated according the maximum length of the values in that column.
My code is:
set colsep ","
spool C:\Oracle\sample.csv
select * from acct_clas_rule;
spool off;
Output of above code is (middle column is having null values)
ABCD_,ABCD_,ABC
-----,-----,---
AB , ,WSD
ABCD , ,WSD
ABCD , ,WSD
SG , ,WSD
KD , ,WSD
WD , ,LKJ
KLHGF, ,LKO
WSDFG, ,LOK
WSDF , ,LKO
WS , ,GH
In above output, columns names have been truncated. I want full names of the columns to be displayed. Can anyone help?
I have seen the question in this link, but I didn't understand how to apply the answers provided there as there was no particular example cited. I am new to these things so I couldn't understand.
Original names of my columns (from left to right in above table) are :
ABCD_DFGT_SDF, ABCD_EDF_GH, ABCD_DFRE
PS -
1. I am using Oracle SQL developer to run sqlplus commands. I think because of which few of my commands are not working (like set underline, set linesize etc.).Please let me know if this is the case. I actually want remove those underlines beneath the columns names.
2. Also let me know that whether you answer is applicable to Oracle SQL Developer or sqlplus.
Thank You
There are a couple of things you can do, in addition to #JChomel's approach - that will work in either SQL Develoepr or SQL*Plus, while these suggestions are specific to SQL Developer.
Let's start with a dummy query based on a CTE to get something like your situation:
set colsep ","
with acct_clas_rule (abdc_1, abcd_2, abcd_3) as (
select cast('AB' as varchar2(5)), cast(null as varchar2(5)), cast('WSD' as varchar2(4)) from dual
union all select 'ABCD', null, 'WSD' from dual
-- ...
union all select 'WS', null, 'GH' from dual
)
select * from acct_clas_rule;
When run as a script in SQL Developer (from the document+arrow icon, or F5) the output is:
ABDC_,ABCD_,ABCD
-----,-----,----
AB , ,WSD
ABCD , ,WSD
WS , ,GH
If you change the query to include the SQL Developer-specific formatting hint /*csv*/ then you get the output you want:
select /*csv*/ * from acct_clas_rule;
"ABDC_1","ABCD_2","ABCD_3"
"AB","","WSD"
"ABCD","","WSD"
"WS","","GH"
except that the strings are all enclosed in double-quotes, which might not be what you really want. (It depends what you're doing with the spooled file and whether any of your string values contain commas, which would confuse Excel for instance).
With more recent versions of SQL Developer you can get exactly the same result without modifying the query using the sqlformat option:
set sqlformat csv
select * from acct_clas_rule;
but again you get the double-quotes. You could change the double-quotes to different enclosure characters, but that probably doesn't help.
A different approach is to use the built-in export tools instead of spool. If you run the query as a statement (green 'play button' icon, or control-enter) then rather than appearing in the Script Output panel, a new Query Result panel will open next to that, showing the results as a grid.
If you right-click on the results you'll get a contextual menu, and choosing Export... from that will give you a wizard to export the results in a format of your choice, including CSV:
You can leave the left and right enclosures as double-quotes to get the same results as the options above, except that null values use the word 'null' instead of an empty string:
"ABDC_1","ABCD_2","ABCD_3"
"AB",null,"WSD"
"ABCD",null,"WSD"
"WS",null,"GH
or you can change them, or remove them by choosing 'none', which gives you:
ABDC_1,ABCD_2,ABCD_3
AB,null,WSD
ABCD,null,WSD
WS,null,G
#thatjeffsmith has commented on how to change the null-replacement text for the /*csv*/ approach. For export it looks like having the word 'null' might have been a bug in 17.2.0; in 17.3.1 that does not appear, and instead you see:
ABDC_1,ABCD_2,ABCD_3
AB,,WSD
ABCD,,WSD
WS,,GH
or enclosed empty strings ("") if you leave the enclosures set.
Q1: TI'm not an expert of SQL Developer. There might be a mode like "command line" or something where you could get similar result, but unsure.
Q2: You have to set the right option to sqlplus: here is a trick I know of (it will also remove the --- --- --- that will cause other issue):
SET HEADING OFF`, to avoid column name to be printed
Union all the column names at the beginning of your script:
set colsep ","
spool C:\Oracle\sample.csv
select 'ABCD_DFGT_SDF', 'ABCD_EDF_GH', 'ABCD_DFRE' from dual
UNION ALL
select * from acct_clas_rule;
spool off;
use the sql plus set command -----> set underline off

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).

NLS_NUMERIC_CHARACTERS setting for decimal

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;

Resources