【附錄】 字符集(一) 漢字在oracle中佔用位元組數

yellowlee發表於2010-05-18

一,漢字在oracle中佔用位元組數

一定要在建庫的時候就選擇好字符集,否則可能給後續的開發或者遷移帶來問題。在開發中字符集問題通常會導致應用層面上的字元越界或者亂碼問題。

先來看看2個使用不同字符集的資料庫:

先來看server1

SQL> select * from v$nls_parameters a ;

 

PARAMETER                                                        VALUE

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

NLS_LANGUAGE                                                     SIMPLIFIED CHINESE

NLS_TERRITORY                                                    CHINA

NLS_CURRENCY                                                     RMB

NLS_ISO_CURRENCY                                                 CHINA

NLS_NUMERIC_CHARACTERS                                           .,

NLS_CALENDAR                                                     GREGORIAN

NLS_DATE_FORMAT                                                  DD-MON-RR

NLS_DATE_LANGUAGE                                                SIMPLIFIED CHINESE

NLS_CHARACTERSET                                                 WE8ISO8859P1

NLS_SORT                                                         BINARY

NLS_TIME_FORMAT                                                  HH.MI.SSXFF AM

NLS_TIMESTAMP_FORMAT                                             DD-MON-RR HH.MI.SSXFF AM

NLS_TIME_TZ_FORMAT                                               HH.MI.SSXFF AM TZR

NLS_TIMESTAMP_TZ_FORMAT                                          DD-MON-RR HH.MI.SSXFF AM TZR

NLS_DUAL_CURRENCY                                                RMB

NLS_NCHAR_CHARACTERSET                                           AL16UTF16

NLS_COMP                                                         BINARY

NLS_LENGTH_SEMANTICS                                             BYTE

NLS_NCHAR_CONV_EXCP                                              FALSE

 

19 rows selected

 

SQL> select '漢字'  from dual;

 

'??'

------

 

再看看server2

SQL> select * from v$nls_parameters a ;

 

PARAMETER                                                        VALUE

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

NLS_LANGUAGE                                                     SIMPLIFIED CHINESE

NLS_TERRITORY                                                    CHINA

NLS_CURRENCY                                                     RMB

NLS_ISO_CURRENCY                                                 CHINA

NLS_NUMERIC_CHARACTERS                                           .,

NLS_CALENDAR                                                     GREGORIAN

NLS_DATE_FORMAT                                                  DD-MON-RR

NLS_DATE_LANGUAGE                                                SIMPLIFIED CHINESE

NLS_CHARACTERSET                                                 AL32UTF8

NLS_SORT                                                         BINARY

NLS_TIME_FORMAT                                                  HH.MI.SSXFF AM

NLS_TIMESTAMP_FORMAT                                             DD-MON-RR HH.MI.SSXFF AM

NLS_TIME_TZ_FORMAT                                               HH.MI.SSXFF AM TZR

NLS_TIMESTAMP_TZ_FORMAT                                          DD-MON-RR HH.MI.SSXFF AM TZR

NLS_DUAL_CURRENCY                                                RMB

NLS_NCHAR_CHARACTERSET                                           AL16UTF16

NLS_COMP                                                         BINARY

NLS_LENGTH_SEMANTICS                                             BYTE

NLS_NCHAR_CONV_EXCP                                              FALSE

 

19 rows selected

 

SQL> select '漢字'  from dual;

 

'漢字'

------

漢字

 

通過比較上述兩個資料庫的區別,發現他們的NLS_CHARACTERSET不同,一個是WE8ISO8859P1,而另外一個是AL32UTF8WE8ISO8859P1是單位元組8位字符集,AL32UTF8是變長多位元組編碼。

現在的客戶端的字符集為:SIMPLIFIED CHINESE_CHINA.ZHS16GBK

WE8ISO8859P1沒有漢字編碼,一般來講,有中文字元就不應該使用這個字符集,雖然修改客戶端和伺服器端相同時可以解決亂碼問題。

有關漢字在oracle中佔用的位元組數問題:

WE8ISO8859P1字符集下,一個漢字佔了1個位元組。

AL32UTF8字符集下面,一個漢字佔了3個位元組。

ZHS16GBK是佔用了2個位元組。

Varchar2varcharnvarchar2均為變長字元型別,char則是固定長度。

vsize函式來看的話很明顯:

Server1:

SQL> select vsize('') from dual;

 

 VSIZE('')

-----------

          1

Server2:

SQL> select vsize('') from dual;

 

 VSIZE('')

-----------

          3

而用length來看,則均為1

Server1

SQL> select length('') from dual;

 

 LENGTH('')

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

           1

Server2

SQL> select length('') from dual;

 

 LENGTH('')

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

           1

 

下面具體來看個對比:

Server1server2中均建立下面的表:

create table t_test_var

(

v_char2 char(2),

v_char3 char(3),

v_varchar22 varchar2(2),

v_varchar23 varchar2(3),

v_varchar2 varchar(2),

v_varchar3 varchar(3),

v_nvarchar22 nvarchar2(2),

v_nvarchar23 nvarchar2(3)

);

然後分別在兩個資料庫中插入測試資料:

Server1:

SQL> insert into t_test_var values ('','','','','','','','');

 

1 row inserted

SQL> insert into t_test_var values ('我們','我們','我們','我們','我們','我們','我們','我們');

 

1 row inserted

SQL> insert into t_test_var values ('我們是','我們是','我們是','我們是','我們是','我們是','我們是','我們是');

 

insert into t_test_var values ('我們是','我們是','我們是','我們是','我們是','我們是','我們是','我們是')

 

ORA-12899: value too large for column "TEST"."T_TEST_VAR"."V_CHAR2" (actual: 3, maximum: 2)

 

說明server1char用一個位元組來儲存一個漢字。

修改一下最後一條插入語句,使得char型別不越界:

 

SQL> insert into t_test_var values ('我們','我們是','我們是','我們是','我們是','我們是','我們是','我們是');

 

insert into t_test_var values ('我們','我們是','我們是','我們是','我們是','我們是','我們是','我們是')

 

ORA-12899: value too large for column "TEST"."T_TEST_VAR"."V_VARCHAR22" (actual: 3, maximum: 2)

 

SQL>

則說明了server1中的varchar2型別也是一個位元組儲存一個漢字,再次修改:

SQL> insert into t_test_var values ('我們','我們是','我們','我們是','我們是','我們是','我們是','我們是');

 

insert into t_test_var values ('我們','我們是','我們','我們是','我們是','我們是','我們是','我們是')

 

ORA-12899: value too large for column "TEST"."T_TEST_VAR"."V_VARCHAR2" (actual: 3, maximum: 2)

則說明varchar也是一個漢字佔一個位元組儲存空間,繼續修改:

 

SQL> insert into t_test_var values ('我們','我們是','我們','我們是','我們','我們是','我們是','我們是');

 

insert into t_test_var values ('我們','我們是','我們','我們是','我們','我們是','我們是','我們是')

 

ORA-12899: value too large for column "TEST"."T_TEST_VAR"."V_NVARCHAR22" (actual: 3, maximum: 2)

則說明nvarchar2也是一個漢字佔一個位元組儲存空間。

這是因為在WE8ISO8859P1字元中,根本沒有漢字編碼。所以得出以上的實驗結果。

 

再來看看Server2:

SQL> insert into t_test_var values ('','','','','','','','');

 

insert into t_test_var values ('','','','','','','','')

 

ORA-01401: inserted value too large for column

SQL> insert into t_test_var values ('我們','我們','我們','我們','我們','我們','我們','我們');

 

insert into t_test_var values ('我們','我們','我們','我們','我們','我們','我們','我們')

 

ORA-01401: inserted value too large for column

SQL> insert into t_test_var values ('我們是','我們是','我們是','我們是','我們是','我們是','我們是','我們是');

 

insert into t_test_var values ('我們是','我們是','我們是','我們是','我們是','我們是','我們是','我們是')

 

ORA-01401: inserted value too large for column

 

SQL> select cast('' as char(1))  from dual;

 

select cast('' as char(1))  from dual

 

ORA-25137: Data value out of range

 

SQL> select cast('' as char(2))  from dual;

 

select cast('' as char(2))  from dual

 

ORA-25137: Data value out of range

 

SQL> select cast('' as char(3))  from dual;

 

CAST(''ASCHAR(3))

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

SQL> insert into t_test_var (v_varchar22) values ('');

 

insert into t_test_var (v_varchar22) values ('')

 

ORA-01401: inserted value too large for column

SQL> insert into t_test_var (v_varchar23) values ('');

 

1 row inserted

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16179598/viewspace-663045/,如需轉載,請註明出處,否則將追究法律責任。

相關文章