Skip to Main Content
  • Questions
  • Do I have to change CHAR(1) to CHAR(1 CHAR)

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Reddy.

Asked: July 11, 2002 - 10:29 pm UTC

Last updated: May 18, 2004 - 12:10 pm UTC

Version: 9.0.1

Viewed 1000+ times

You Asked


I have a table which is expected to hold multi-lingual data.

Part of the table definition.

STATEMENT_STATE
STATEMENT_STATE_ID
STATEMENT_NAME VARCHAR2(50 CHAR)
STATEMENT_STATE_CHANGE CHAR(1)
State change info. Allowed values 'C' (created), 'U' (updated) and 'D' (deleted).
STATEMENT_PENDING_IND CHAR(1)
Pending Status Indicator Y Yes pending N Not pending
:
:

Check Constraints
CKSTATEMENT_PENDING_IND --> STATEMENT_PENDING_IND IN ('Y', 'N')
CKSTATEMENT_STATE_CHANGE --> STATEMENT_STATE_CHANGE IN (’C’,’U’,’D’)

Database NLS_LANG set to UTF-8.

We use a multitier Unicode solution. i.e all-UTF8 architecture. Similar to the one explained in 9.0.1 Oracle documentation ref. # a90236, Globalization Support Guide ref nls81030.gif

My question is do I have to change CHAR(1) to CHAR(1 CHAR) ?

What value will be populated in the db if a Japanese client selects 'Y' in the on-line.
Is that still 'Y' or equivalent Japanese character?

I guess following should be considered.

Restrictions due to constraint
· Check Constraint will not allow other values in that column

Code restrictions
In the code I guess we always use actual English characters.
IF STATEMENT_PENDING_IND = ’N’
DO SOME THING
ELSE
DO NOTHING.

Thanks
Reddy


and Tom said...

You don't have to but if you hit a language where C, U or D takes more then one byte -- you will WISH you did.

It would be a good idea to use the char(N char) and varchar2(N char) everywhere in new development.

Rating

  (8 ratings)

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

Comments

One clarification please

reddy ks, July 12, 2002 - 1:10 pm UTC

I guess, the character Y goes into db as Y or C as C.
But it may take more than 1 byte if a Japanese client or a Chinese client enter's the value instead of English Client.

Which Data Dictionary object stores CHAR ?

Reddy KS, July 12, 2002 - 2:31 pm UTC

I was able to see the details (in specific CHAR ) in SQL Plus when I did 

SQL>desc STATEMENT_STATE

But when I do select * from cols, it is not showing CHAR.


These are the additional cols in 9.0.1 vs 8.1.7.
CHAR_LENGTH            
CHAR_USED              
V80_FMT_IMAGE          
DATA_UPGRADED          

But none of these columns are storing the string CHAR.
Where do Oracle stores CHAR.

Thanks
Reddy 

Tom Kyte
July 12, 2002 - 5:48 pm UTC

quick peek into the documentation for the meaning and we find (surprisingly)

CHAR_USED VARCHAR2(1)
B | C.

B indicates that the column uses BYTE length
semantics. C indicates that the column uses CHAR length
semantics. NULL indicates the datatype is not any of the
following:

n CHAR
n VARCHAR2
n NCHAR
n NVARCHAR2


so, char_used is what you are looking for and a B or C will tell you Bytes or Characters.

char(1) and char (1 char)

Brijesh, December 24, 2002 - 2:02 am UTC

Mr. Tom I downloaded you presentation slides of oracle 9i
</code> http://asktom.oracle.com/~tkyte/9iClass/index.html <code>

in that demo0013.sql gave me the following :

demo@ORA92> @E:\mak\oracle\ask-tom\Presentations\9iTrain\9iTrain\demo013
demo@ORA92>
demo@ORA92> create table t ( a char(1), b char( 1 char ), c char(2000 char) );

Table created.

demo@ORA92>
demo@ORA92> insert into t (a) values ( unistr( '\00d6') );

1 row created.

demo@ORA92>
demo@ORA92> insert into t (b) values ( unistr( '\00d6') );

1 row created.

demo@ORA92>
demo@ORA92> select length(b), lengthb(b), dump(b) dump from t;

LENGTH(B) LENGTHB(B)
---------- ----------
DUMP
--------------------------------------------------------------------------------------------

NULL

1 1
Typ=96 Len=1: 63


demo@ORA92>
demo@ORA92> insert into t (c) values ( rpad( unistr( '\00d6'), 2000, unistr('\00d6') ) );

1 row created.

demo@ORA92>
demo@ORA92> insert into t (c) values ( rpad( unistr( '\00d6'), 1001, unistr('\00d6') ) );

1 row created.

demo@ORA92>
demo@ORA92> insert into t (c) values ( rpad( unistr( '\00d6'), 1000, unistr('\00d6') ) );

1 row created.

demo@ORA92>
demo@ORA92> drop table t;

Table dropped.

But according to your slides when you enter a unicode character which is more than one byte into a char(1) column it should give an error which is'nt the case here.

My DB CharSet is :
AMERICAN_AMERICA.WE8MSWIN1252

Any comments,
Thanks.


Tom Kyte
December 24, 2002 - 8:32 am UTC

You need a UTF8 database for that demo to make sense.

sorry that was not more clear on these two slides:

</code> http://asktom.oracle.com/~tkyte/9iClass/img23.html <code>

It is in the sql prompt and it is the reason why I have a cut and paste of the sqlplus sesssion on those slides. Unless you have a UTF8 database -- the demo won't show you anything as the characters will all be convered to single byte data in your database anyway.

OK

Mary, November 25, 2003 - 7:13 am UTC

Dear Sir,
I tried the following code snippet but got errors.Could you
please correct this? and is there any other way that this
code can be made to work?
SQL> begin
  2   for c in chr(ascii('a')) .. chr(ascii('z')) loop
  3    dbms_output.put(c); 
  4   end loop;               
  5   dbms_output.put_line(' ');
  6  end;
  7  /
begin
*
ERROR at line 1: 
ORA-06550: line 2, column 11: 
PLS-00364: loop index variable 'CHR' use is invalid 
ORA-06550: line 2, column 2: 
PL/SQL: Statement ignored 


I want the alphabets a..z to be printed.Could you please help?
Thanks in advance

 

Tom Kyte
November 25, 2003 - 8:12 am UTC

that loop is not really any differen then:

ops$tkyte@ORA920PC> begin
  2     for c in 'a' .. 'z'
  3     loop
  4        dbms_output.put_line( c );
  5     end loop;
  6  end;
  7  /
begin
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 2
 

<b> you need to iterate over a NUMBER.  perhaps this is what you want:</b>
 

ops$tkyte@ORA920PC> begin
  2     for i in ascii('a') .. ascii('z')
  3     loop
  4        dbms_output.put_line( chr(i) );
  5     end loop;
  6  end;
  7  /
a
b
c
d
 

Are you sure...

Nick, November 25, 2003 - 12:46 pm UTC

"It would be a good idea to use the char(N char) and varchar2(N char) everywhere in new development."

This statement seems to violate the concept of using data types to help enforce integrity. If I have a field that I know will never hold anything other than US ascii I would use varchar2(N) and if I have a field than will be used to store international characters I would use varchar2(N char).

Our application under development right now is a perfect example of this. We use many alphanumic codes and these are all defined as varchar2(N). International characters as codes wouldn't make sense to us. We have other fields that can store names from around the world and these are varchar2(N char). Isn't this an appropriate approach?

Tom Kyte
November 25, 2003 - 1:33 pm UTC

if you have a field

that you know will only hold US ASCII 7

then varchar2(10 char) is plug identical to varchar2(10)

how does that violate any concepts????? In a usascii7 database -- a char is a byte. this only comes to play in a multi-byte database (and then you cannot SAY that the ascii characters will all be SINGLE BYTE)

a character is a character, that is all. this does not "violate" anything.

Trying again...

Nick, November 25, 2003 - 3:21 pm UTC

The database supports multi-byte data.

One field will only hold data like 'abc' so it is varchar2(3). It will never have international characters. Another field can hold international characters so it is varchar2(3 char).

Why is this not a better approach than your recommendation of using varchar2(N char) throughout the application?

Tom Kyte
November 25, 2003 - 3:55 pm UTC

do you know for a fact that in the characterset of your clients, abc will be all single byte data (i cannot say that, I don't even know if it is true)

i can say

"the field is to hold 3 characters"

varchar2(3 char)

holds -- well, 3 characters.

varchar2(3)

holds -- 3 bytes, which is going to be 3 or LESS characters.

there is no such thing as "regular" and "international" characters, the client has a characterset.



A reader, January 02, 2004 - 5:02 pm UTC


character semantics

Venkat, May 18, 2004 - 6:08 am UTC

Tom,

(1) Towards globalization of the existing application on oracle 9i, to set the character semantics, is the following correct?

1. Take export of the application schema.
2. Change the nls length semantics to CHAR using alter system command.
3. restart the instance, drop the schema.
4. create the schema again and do import.

anthing is missed out here?

(2) Which is the best way to achieve this towards globalization for the existing applications on 8i?

(3) Is changing the width of all char and varchar2 four times of the existing size would be the best option to achieve this in our application running both on 8i and 9i?

Regards,
Venkat

Tom Kyte
May 18, 2004 - 12:10 pm UTC

1) not sure what path you are going down there. It would seem you would want to use a new characterset -- if the one you were using didn't support the data you ultimately wanted to store.

2) not sure what your needs are.

3) depends on your needs. if you use a multi-byte character set, you'll have to remember that a varchar2(80) holds 80 *bytes*, not 80 characters and accomidate for that.