天天看點

oracle中imp導入資料中文亂碼問題

用imp指令向oracle中導入資料後,所有查詢出的中文字段都為亂碼.

1.       原則上不修改伺服器端的字元集,修改伺服器端的字元集會出現使用第三方工具登陸資料庫出現亂碼的情況(具體伺服器端的字元集修改辦法本文有詳細介紹)。

2.       将DMP檔案的字元集改成與Oracleo資料庫伺服器端一樣之後導入可正常顯示。本人的系統是RHEL 5.4 32bit

一、什麼是oracle字元集

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

影響oracle資料庫字元集最重要的參數是NLS_LANG參數。它的格式如下:

NLS_LANG = LANGUAGE_TERRITORY.CHARSET

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

Language 指定伺服器消息的語言,territory 指定伺服器的日期和數字格式,charset 指定字元集。如:AMERICAN _ AMERICA. UTF8

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

二、如何查詢Oracle的字元集

很多人都碰到過因為字元集不同而使資料導入失敗的情況。這涉及三方面的字元集:

1.         oracel server端的字元集。

2.         oracle client端的字元集。

3.         DMP檔案的字元集。

在做資料導入的時候,需要這三個字元集都一緻導入後才會不出現亂碼。

查詢oracle server端的字元集

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

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

USERENV('LANGUAGE')

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

AMERICAN_AMERICA.UTF8

SQL>

結果類似如下: AMERICAN_AMERICA.UTF8

如何查詢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檔案很大,比如有2G以上(這也是最常見的情況),用文本編輯器打開很慢或者完全打不開,可以用以下指令(在unix主機上):

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

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

0345

$

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

查詢oracle client端的字元集

在Linux/UNIX平台下,就是環境變量NLS_LANG。

$echo $NLS_LANG

AMERICAN_AMERICA.UTF8

在windows平台下,系統資料庫裡面的HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0\NLS_LANG。還可以在DOS視窗裡面臨時設定,比如:set nls_lang=AMERICAN_AMERICA.UTF8

這樣就隻影響這個視窗裡面的環境變量。

請確定server端與client端字元集相一緻。

三、修改oracle的字元集

oracle的字元集有互相的包容關系。如US7ASCII就是ZHS16GBK的子集,從US7ASCII到ZHS16GBK不會有資料解釋上的問題,不會有資料丢失。在所有的字元集中UTF8應該是最大,因為它基于UNICODE,雙位元組儲存字元(也是以在存儲空間上占用更多)。

一旦資料庫建立後,資料庫的字元集理論上講是不能改變的。根據Oracle的官方說明,字元集的轉換是從子集到超集,反之不行。如果兩種字元集之間根本沒有子集和超集的關系,那麼字元集的轉換是不受Oracle支援的。在修改之前一定要确認兩種字元集是否存在子集和超集的關系。一般來說,除非萬不得已,我們不建議修改oracle資料庫server端的字元集。

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

關于字元集的對應關系可以檢視Oracle官方說明:

http://download.oracle.com/docs/cd/B19306_01/server.102/b14225/applocaledata.htm

修改server端字元集(不建議使用)

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

$sqlplus “/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 INTERNAL_USE UTF8;  //跳過超子集檢測

SQL>ALTER DATABASE national CHARACTER SET INTERNAL UTF8;

這一行不起作用,執行後出錯ORA-00933: SQL 指令未正确結束,不過執行上一行指令已經生效,其他文章裡未提到本行。

SQL>SHUTDOWN IMMEDIATE;

SQL>STARTUP;

修改DMP檔案字元集

DMP檔案的第2第3位元組記錄了字元集資訊,是以直接修改DMP檔案的第2第3位元組的内容就可以騙過oracle的檢查。理論上也僅是從子集到超集可以修改,但很多情況下在沒有子集和超集關系的情況下也可以修改,我們常用的一些字元集,如US7ASCII,WE8ISO8859P1,ZHS16CGB231280,ZHS16GBK基本都可以改。因為改的隻是DMP檔案,是以影響不大。

具體的修改方法比較多,最簡單的就是直接用UltraEdit修改DMP檔案的第2和第3個位元組。比如想将DMP檔案的字元集改為UTF8,可以用以下SQL查出該種字元集對應的16進制代碼:

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

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

TO_CH

-----

  367

SQL>

然後将DMP檔案的2、3位元組修改為0367即可。

如果DMP檔案很大,用UltraEdit無法打開,就需要用其它方法的方法了。

更多資訊請登陸我的網站:www.yeserver.com