close


原文出處:http://www.hkitn.com/article.php/5902
(註:部分文字稍稍修正及調整排版)

經常有同事咨詢 Oracle 資料庫字元集相關的問題,如在不同資料庫做數據
遷移、同其它系統交換數據等,常常因為字元集不同而導致遷移失敗或資料
庫內數據變成亂碼。現在我將 Oracle 字元集相關的一些知識做個簡單總結,
希望對大家今後的工作有所幫助。

本文從定義入手來講解對 Oracle 資料庫字元集如何全面認識。

一、什麼是 Oracle 字元集

    Oracle 字元集是一個位元組數據的解釋的符號集合,有大小之分,有相互
    的包容關係。Oracle 支援國家語言的體系結構允許你使用本地化語言來
    存儲,處理,檢索數據。它使資料庫工具,錯誤消息,排序次序,日期,
    時間,貨幣,數字,和日曆自動適應本地化語言和平台。

    影響Oracle資料庫字元集最重要的參數是 NLS_LANG 參數。

    它的格式如下:

    NLS_LANG = language_territory.charset

    它有三個組成部分(語言、地域和字元集),每個成分控制了 NLS 子集的
    特性,其中:

    Language 指定伺服器消息的語言,

    territory 指定伺服器的日期和數字格式,

    charset 指定字元集。

    例如: AMERICAN_AMERICA.ZHS16GBK

    從 NLS_LANG 的組成我們可以看出,真正影響資料庫字元集的其實是第三
    部分。所以兩個資料庫之間的字元集只要第三部分一樣就可以相互導入導
    出數據,前面影響的只是提示資訊是中文還是英文。

二、如何查詢 Oracle 的字元集

    很多人都碰到過因為字元集不同而使數據導入失敗的情況。

    這涉及三方面的字元集:

        1. 是 Oracle Server端的字元集。
        2. 是 Oracle Client端的字元集。
        3. 是 dmp 文件的字元集。

    在做數據導入的時候,需要這三個字元集都一致才能正確導入。

    1、查詢 Oracle Server端的字元集

        有很多種方法可以查出 Oracle Server 端的字元集,比較直觀的查詢
        方法是以下這種:

        SQL> select userenv('language') from dual;

        結果類似如下:

        AMERICAN_AMERICA. ZHS16GBK

    2、如何查詢 dmp 文件的字元集

        用 Oracle 的 exp 工具導出的 dmp 文件也包含了字元集資訊, dmp
        文件的第 2 和第 3 個位元組記錄了 dmp 文件的字元集。如果 dmp
        文件不大,比如只有幾 M 或幾十 M,可以用 UltraEdit 打開 (16進制
        方式),看第 2 和第 3 個位元組的內容,如 0354,然後用以下 SQL
        查出它對應的字元集:

        SQL> select nls_charset_name(to_number('0354','xxxx')) from dual;

        結果類似如下:

        ZHS16GBK

        如果 dmp 文件很大,比如有 2 G 以上 (這也是最常見的情況),用文本
        編輯器打開很慢或者完全打不開,可以用以下命令 (在 unix 主機上):

        cat exp.dmp |od -x|head -1|awk '{print $2 $3}'|cut -c 3-6

        然後用上述 SQL 也可以得到它對應的字元集。

    3、查詢 Oracle Client端的字元集

        這個比較簡單。在 Windows 平台下,就是註冊表裏面相應 OracleHome
        的 NLS_LANG。還可以在 Dos 窗口裏面自己設定,比如:

        set nls_lang=AMERICAN_AMERICA.ZHS16GBK

        這樣就只影響這個窗口裏面的環境變量。

        在 unix 平台下,就是環境變量 NLS_LANG。

        $echo $NLS_LANG

        AMERICAN_AMERICA.ZHS16GBK

        如果檢查的結果發現 Server 端與 Client 端字元集不一致,請統一
        修改為與 Server 端相同的字元集。

三、修改 Oracle 的字元集

    上文說過,Oracle 的字元集有互相的包容關係。

    如 US7ASCII 就是 ZHS16GBK 的子集,從 US7ASCII 到 ZHS16GBK 不會有
    數據解釋上的問題,不會有數據丟失。

    在所有的字元集中 utf8 應該是最大,因為它基於 unicode,雙位元組保存
    字元 (也因此在存儲空間上佔用更多)。

    一旦資料庫創建後,資料庫的字元集理論上講是不能改變的。因此,在設計
   和裝設之初考慮使用哪一種字元集十分重要。

   根據 Oracle 的官方說明,字元集的轉換是從子集到超集受支援,反之不行。
   如果兩種字元集之間根本沒有子集和超集的關係,那麼字元集的轉換是不受
   Oracle 支援的。

   對資料庫 Server 而言,錯誤的修改字元集將會導致很多不可測的後果,可能
   會嚴重影響資料庫的正常運行,所以在修改之前一定要確認兩種字元集是否存
   在子集和超集的關係。一般來說,除非萬不得已,我們不建議修改 Oracle 資
   料庫 Server 端的字元集。

   特別說明,我們最常用的兩種字元集 ZHS16GBK 和 ZHS16CGB231280 之間不
   存在子集和超集關係,因此理論上講這兩種字元集之間的相互轉換不受支援。

    1、修改 Server 端字元集(不建議使用)

        在 Oracle 8之前,可以用直接修改數據字典表 props$ 來改變資料庫的
        字元集。但 Oracle 8 之後,至少有三張系統表記錄了資料庫字元集的
        資訊,只改 props$ 表並不完全,可能引起嚴重的後果。正確的修改方
        法如下:

        $sqlplus /nolog

        SQL> conn / as sysdba;

        若此時資料庫伺服器已啟動,則先執行 SHUTDOWN IMMEDIATE 命令關閉
        資料庫伺服器,然後執行以下命令:

        SQL> STARTUP MOUNT;

        SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;

        SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;

        SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;

        SQL> ALTER DATABASE OPEN;

        SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;

        SQL> ALTER DATABASE national CHARACTER SET ZHS16GBK;

        SQL> SHUTDOWN IMMEDIATE;

        SQL> STARTUP

    2、修改 dmp 文件字元集

        上文說過,dmp 文件的第 2 第 3 位元組記錄了字元集資訊,因此直接
        修改 dmp 文件的第 2 和第 3 位元組的內容就可以「騙」過 Oracle 的
        檢查。

        這樣做理論上也僅是從子集到超集可以修改,但很多情況下在沒有子集
        和超集關係的情況下也可以修改,我們常用的一些字元集,如:

        US7ASCII、WE8ISO8859P1、ZHS16CGB231280、ZHS16GBK

        基本都可以改。因為改的只是 dmp 文件,所以影響不大。

        具體的修改方法比較多,最簡單的就是直接用 UltraEdit 修改 dmp 文
        件的第 2 和第 3 個位元組。

        比如想將 dmp 文件的字元集改為 ZHS16GBK,可以用以下 SQL 查出該種
        字元集對應的 16 進制代碼:

        SQL> select to_char(nls_charset_id('ZHS16GBK'), 'xxxx') from dual;

        0354

        然後將 dmp 文件的 2、3 位元組修改為 0354 即可。

        如果 dmp 文件很大,用 UltraEdit 無法打開,就需要用程式的方法了。

        網上有人用 java 存儲過程寫了轉換的程式 (用 java 存儲過程的好處
        是通用性教好,缺點是比較麻煩)。我在 Windows 下測試過。但要求
        Oracle 資料庫一定要裝設 JVM 選項。有興趣的朋友可以研究一下程式
        代碼。

===

arrow
arrow
    全站熱搜

    Cliff 發表在 痞客邦 留言(0) 人氣()