【字符集】論Oracle字符集“轉碼”過程

secooler發表於2010-02-05
本文將通過實驗來演示一下Oracle字符集“轉碼”的確認過程。

曾經分享過的有關字符集文章如下:
《檢視本地windows的字符集方法》
http://space.itpub.net/519536/viewspace-580610
《【字符集】“客戶終端字符集”、“NLS_LANG”環境變數以及“資料庫字符集”》
http://space.itpub.net/519536/viewspace-615345
《【字符集】處理Toad顯示亂碼及Windows XP下無法插入“某些漢字”問題》
http://space.itpub.net/519536/viewspace-615379

OK,現在開始我們的實驗之旅。

1.實驗環境說明
客戶端是Windows XP作業系統的SQL*Plus程式,客戶端字符集是936(對應Oracle的
ZHS16GBK字符集);
資料庫版本是Oracle 10g,資料庫字符集是AL32UTF8;
NLS_LANG引數將在實驗中進行指定。

1)確認客戶端字符集
C:\>chcp
活動內碼表: 936

註釋:936對應Oracle的ZHS16GBK字符集。

2)檢視資料庫版本資訊:
sec@ora10g> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE    10.2.0.3.0      Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production

3)確認資料庫的字符集:
sec@ora10g> col PARAMETER for a20
sec@ora10g> col value for a20
sec@ora10g> select * from v$nls_parameters where parameter = 'NLS_CHARACTERSET';

PARAMETER            VALUE
-------------------- --------------------
NLS_CHARACTERSET     AL32UTF8

2.實驗中將會涉及到的兩種場景
“轉碼”場景:設定客戶端的NLS_LANG與客戶端字符集一致,這裡是ZHS16GBK;
“非轉碼”場景:設定客戶端的NLS_LANG與資料庫伺服器端字符集一致,此處是AL32UTF8.
關於如何設定NLS_LANG引數,請參考下面文章:
《【NLS_LANG】不同作業系統平臺NLS_LANG環境變數的檢視與設定方法》
http://space.itpub.net/519536/viewspace-580623
在這個實驗中,為了方便,我將採用set命令設定字符集。您可以按照自己的習慣去設定。

3.建立實驗表T
sec@ora10g> create table t (x number(1), client_characterset varchar2(10), nls_lang varchar2(10), database_characterset varchar2(10), y varchar2(10));

Table created.

sec@ora10g> desc t;
 Name                                Null?    Type
 ----------------------------------- -------- ------------------------
 X                                            NUMBER(1)
 CLIENT_CHARACTERSET                          VARCHAR2(10)
 NLS_LANG                                     VARCHAR2(10)
 DATABASE_CHARACTERSET                        VARCHAR2(10)
 Y                                            VARCHAR2(10)

T表包含五個欄位,分表表示序號、客戶端字符集、客戶端NLS_LANG設定情況以及資料庫伺服器字符集設定情況。

4.兩種NLS_LANG設定方法下分別插入一條資料
1)當客戶端的NLS_LANG設定為ZHS16GBK時,我們插入第一條記錄(“轉碼”場景)。
C:\>set nls_lang=AMERICAN_AMERICA.ZHS16GBK

C:\>sqlplus sec/sec@ora10g

SQL*Plus: Release 10.2.0.3.0 - Production on Fri Feb 5 19:21:31 2010

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning and Data Mining options

sec@ora10g> insert into t values (1,'ZHS16GBK','ZHS16GBK','AL32UTF8','聖');

1 row created.

sec@ora10g> commit;

Commit complete.

2)當客戶端的NLS_LANG設定為AL32UTF8時,我們插入第二條記錄(“非轉碼”場景)。
C:\>set nls_lang=AMERICAN_AMERICA.AL32UTF8

C:\>sqlplus sec/sec@ora10g

SQL*Plus: Release 10.2.0.3.0 - Production on Fri Feb 5 20:41:15 2010

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning and Data Mining options

sec@ora10g> insert into t values (2,'ZHS16GBK','AL32UTF8','AL32UTF8','聖');

1 row created.

sec@ora10g> commit;

Commit complete.

5.兩種NLS_LANG設定方法下分別檢視剛剛插入的兩條資料
1)當客戶端的NLS_LANG設定為ZHS16GBK時(“轉碼”場景)。
sec@ora10g> col x for 9
sec@ora10g> col CLIENT_CHARACTERSET for a8
sec@ora10g> col NLS_LANG for a8
sec@ora10g> col DATABASE_CHARACTERSET for a8
sec@ora10g> col y for a4
sec@ora10g> col dump for a50
sec@ora10g> select t.*,dump(y,1016) dump from t order by 1;

 X CLIENT_C NLS_LANG DATABASE Y    DUMP
-- -------- -------- -------- ---- --------------------------------------------------
 1 ZHS16GBK ZHS16GBK AL32UTF8 聖   Typ=1 Len=3 CharacterSet=AL32UTF8: e5,9c,a3
 2 ZHS16GBK AL32UTF8 AL32UTF8 ?   Typ=1 Len=2 CharacterSet=AL32UTF8: ca,a5


2)當客戶端的NLS_LANG設定為AL32UTF8時(“非轉碼”場景)。
sec@ora10g> col x for 9
sec@ora10g> col CLIENT_CHARACTERSET for a8
sec@ora10g> col NLS_LANG for a8
sec@ora10g> col DATABASE_CHARACTERSET for a8
sec@ora10g> col y for a4
sec@ora10g> col dump for a50
sec@ora10g> select t.*,dump(y,1016) dump from t order by 1;

 X CLIENT_C NLS_LANG DATABASE Y    DUMP
-- -------- -------- -------- ---- --------------------------------------------------
 1 ZHS16GBK ZHS16GBK AL32UTF8 鍦?  Typ=1 Len=3 CharacterSet=AL32UTF8: e5,9c,a3
 2 ZHS16GBK AL32UTF8 AL32UTF8 聖    Typ=1 Len=2 CharacterSet=AL32UTF8: ca,a5


BTW:有關dump函式的使用方法可以參考Oracle的官方文件
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions046.htm#SQLRF00635
我這裡將return_fmt指定為“1016”,這樣會指示出字符集和字元的16進位制編碼內容。

6.分析與結論
1)“聖”字在ZHS16GBK字符集下的編碼是“ca,a5”
這個資訊可以從微軟的936字符集(ZHS16GBK)中查詢得到。
http://www.microsoft.com/globaldev/reference/dbcs/936/936_CA.mspx
【字符集】論Oracle字符集“轉碼”過程

2)“聖”字在AL32UTF8字符集下的編碼是“e5,9c,a3”

怎麼確認“聖”字在UTF8字符集下的編碼呢?使用UltraEdit的十六進位制編輯模式可以完成這個任務。
將漢字“聖”貼上到空白的UltraEdit中,依次點選“檔案” --&gt “轉換” --&gt “ASCII轉UTF-8(Unicode 編輯)”,然後再一次點選“編輯” --&gt “十六進位制函式” --&gt “十六進位制編輯”(反覆切換十六進位制編輯模式亦可使用Ctrl+H快捷鍵來完成),OK,此時便可以得到“聖”字在UTF8字符集下的編碼是“E5 9C A3”。
當然,確認“聖”字在ZHS16GBK字符集下的編碼也可以使用UltraEdit來完成。

3)結論一
當客戶端的NLS_LANG設定為ZHS16GBK時,“聖”字發生了轉碼,由
ZHS16GBK編碼“ca,a5”轉成了AL32UTF8編碼“e5,9c,a3”;

4)結論二
當客戶端的NLS_LANG設定為AL32UTF8時,“聖”字沒有發生轉碼,直接以客戶端的
ZHS16GBK編碼“ca,a5”儲存在資料庫中。

5)“?”的由來
當客戶端的NLS_LANG設定為ZHS16GBK時,查詢得到的“?”是由UTF-8編碼“ca,a5”轉換為ZHS16GBK編碼後的產物。

6)“鍦?”的由來
這個“鍦”字讀作“shi1”(參考:http://www.zdic.net/zd/zi/ZdicE9Zdic8DZdicA6.htm
因為此時NLS_LANG設定為AL32UTF8,客戶端獲取資料庫資訊時將不進行轉碼,因此在客戶端顯示的時候將使用“e5,9c,a3”這個編碼在936字符集(ZHS16GBK)中尋找匹配的內容。前面的“e5,9c”正好拼接成了“鍦”字,因此“鍦”字便展現在了我們面前。
這個“鍦”字的編碼可以在下面的連結中查詢到。
http://www.microsoft.com/globaldev/reference/dbcs/936/936_E5.mspx
【字符集】論Oracle字符集“轉碼”過程

7.小結
Oracle字符集相關知識涉及面較廣,需要靜下心來仔細思考其中蘊含的原理。
本文通過實驗給大家展示了有關“轉碼”的相關內容,供參考,希望對大家有幫助。

Good luck.

secooler
10.02.05

-- The End --

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

相關文章