1. 程式人生 > >關於Oracle一個漢字代表幾個位元組的問題

關於Oracle一個漢字代表幾個位元組的問題

在Oracle定義變數時,常有VARCHAR2 (3 Char)或者VARCHAR2 (10 Byte)的資料型別,那麼3char或者10Byte到底代表幾個漢字,幾個字元呢,上次外公司一同事討論這個問題,一下沒給解釋清楚,所以下來以後整理如下:

總結:
當NLS_CHARACTERSET=AL32UTF8時()
NLS_LENGTH_SEMANTICS=BYTE時,一個漢字代表三個位元組
NLS_LENGTH_SEMANTICS=CHAR時,一個漢字代表一個位元組
當NLS_CHARACTERSET=US7ASCII時(字符集為單位元組)
NLS_LENGTH_SEMANTICS=BYTE時,一個漢字代表兩個位元組
NLS_LENGTH_SEMANTICS=CHAR時,一個漢字代表兩個位元組

現象:
select * from nls_database_parameters;
….      …………..
NLS_CHARACTERSET        AL32UTF8

…..

NLS_LENGTH_SEMANTICS BYTE

….

NLS_NCHAR_CHARACTERSET      AL16UTF16

NLS_RDBMS_VERSION      10.2.0.4.0
 

SQL> alter session set nls_length_semantics='BYTE';

SQL> create table nls_byte(c1 varchar2(7));

SQL> insert into nls_byte values('測試機');

 insert into nls_byte values('測試機')

 ORA-12899: 列 "SYS"."NLS_BYTE"."C1" 的值太大 (實際值: 9, 最大值: 7)

SQL> insert into nls_byte values('測試a');

 1 row inserted
 
SQL> select table_name,column_name,t.DATA_TYPE,t.DATA_LENGTH,t.CHAR_USED from user_tab_columns t where table_name='NLS_BYTE';

 TABLE_NAME COLU DATA_TYP DATA_LENGTH CHAR_USED

---------- ---- -------- ----------- ---------

NLS_BYTE   C1   VARCHAR2           7 B
  
NLS_LENGTH_SEMANTICS allows you to specify the length of a column datatype in terms of CHARacters rather than in terms of BYTEs. Typically this is when using an AL32UTF8 or other varying width NLS_CHARACTERSET database where one character is not always one byte. While using CHAR semantics has as such no added value in a 7/8 bit characterset it's fully supported so any application code / table setup using CHAR can also be used in a 7/8bit characterset like US7ASCII/WE8MSWIN1252.
This parameter is a 9i (and up) feature and is not available in older releases

翻譯過來就是:這個引數允許將列的資料單位設為字元而不是byte.這個問題會在字符集設為UTF8的時候出現. 此引數在9i以上版本有效.

NLS_LENGTH_SEMANTICS 設定.

1.      NLS_DATABASE_PARAMETERS中的值是在資料庫建立的時候確定的,一般都為BYTE

2.     此引數可以以 “ALTER SYSTEM SET NLS_LENGTH_SEMANTICS=CHAR scope=both”方式修改,但是需要重啟資料庫才能生效.

3.     也可用” ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR”使對當前session生效.

4.     此引數可以在10G以上版本中,在環境變數或登錄檔中設定(注意需要大寫),設定後從當前客戶端啟動的所有會話都採用新的取值.

5.     修改後只對新建的列生效,對於已有的列沒有作用

6.     新建或升級DB時用BYTE,否則XDB或dba_tables會出現問題.

7.     NLS_LENGTH_SEMANTICS對sys使用者下的物件無效.

8.     如果對於7/8bit的字符集,設為byte/char意義不大,因為無論是char和byte都對應一個byte.

測試:

一.在當前session中修改此引數

 SQL> alter session set nls_length_semantics='char';

 Session altered

 SQL> create table nls_char(c1 varchar2(7),c2 varchar2(7));

 Table created

 SQL> desc nls_char

Name Type        Nullable Default Comments

---- ----------- -------- ------- --------

C1   VARCHAR2(7) Y                      

C2   VARCHAR2(7) Y                      

 SQL> insert into nls_char values('測試機','測試測試測試');

 1 row inserted 

如果對於alter system,效果是一樣的

二.對於已經存在的表,

 SQL> desc nls_byte

Name Type             Nullable Default Comments

---- ---------------- -------- ------- --------

C1   VARCHAR2(7 BYTE) Y                      

SQL> alter table nls_byte modify c1 varchar2(7 char);

 Table altered

 SQL> desc nls_byte

Name Type        Nullable Default Comments

---- ----------- -------- ------- --------

C1   VARCHAR2(7) Y                      

 SQL> insert into nls_byte values('測試機');

 1 row inserted
 
1.      exp/imp : 不能直接匯入,因為會採用source table的建表方式在target db裡建表,即使目標庫設的值為char.

*可以預先在目標庫中以char方式建表

*然後匯入,指定引數ignore=y

  2. Alter table

     alter table "<owner>"."<table>" modify "<column>" char (10 char);

      建立指令碼,修改列設定.

 注:

Bug-3611750, ora-01450 online rebuild of index fails, 可以在重建索引前指定byte, 10.2.0.5以上已經修復

Bug 1488174 UNICODE: ALTER SYSTEM SET NLS_LENGTH_SEMANTICS DOESN'T
TAKE EFFECT, 用此語句修改後,實際上不起作用,需要重啟才能生效, 但是如果用alter session方式即時生效,不用重啟.

進一步測試,在另一個字符集設為us7ascii的DB設定此引數

SQL> select * from nls_database_parameters

6          NLS_CHARACTERSET  US7ASCII

SQL> alter session set nls_length_semantics=byte;

Session altered.

SQL> create table nls_byte(c1 varchar2(7));

Table created.

SQL> insert into  nls_byte values('測試測試');

insert into  nls_byte values('測試測試')

ERROR at line 1:

ORA-12899: value too large for column "TEA"."NLS_BYTE"."C1" (actual: 8,

maximum: 7)

SQL> desc nls_byte

 Name                        Null?    Type

 -------------------------------

 C1                                   VARCHAR2(7)

SQL> alter session set nls_length_semantics=char;

Session altered.

SQL> create table nls_char(c1 varchar2(7));

Table created.

SQL> insert into  nls_char values('測試測試');

insert into  nls_char values('測試測試')

ERROR at line 1:

ORA-12899: value too large for column "TEA"."NLS_CHAR"."C1" (actual: 8,

maximum: 7)

SQL> desc nls_char

 Name                        Null?    Type

 ----------------------------------------- -------- -------------------

C1                                  VARCHAR2(7)
 
 可以看出,在字符集為單位元組的情況下,無論取何值,漢字都是以二個位元組的方式存在的.


本文轉自http://www.wudeyao.com/post-69.html