字符集問題的初步探討(四)
2024-07-21 02:07:14
供稿:網友
本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。
link:
http://www.eygle.com/special/nls_character_set_04.htm
4. 導入導出及轉換
導入導出是我們常用的一個數據遷移及轉化工具,因其導出文件具有平臺無關性,所以在跨平臺遷移中,最為常用。
在導出操作時,非常重要的是客戶端的字符集設置,也就是客戶端的nls_lang設置。
nls_lang參數由以下部分組成:
nls_lang=<language>_<territory>.<clients characterset>
nls_lang各部分含義如下:language指定:-oracle消息使用的語言-日期中月份和日顯示territory指定-貨幣和數字格式-地區和計算星期及日期的習慣characterset:-控制客戶端應用程序使用的字符集通常設置或者等于客戶端(如windows)代碼頁或者對于unicode應用設置為utf8在windows上查看當前系統的代碼頁可以使用chcp命令:
e:/>chcp
活動的代碼頁: 936
代碼頁936也就是中文字符集 gbk,在microsoft的官方站點上,我們可以遭到關于936代碼頁的具體編碼規則,請參考以下鏈接:
http://www.microsoft.com/globaldev/reference/dbcs/936.htm
我們看一個簡單的測試,來了解一下這幾個參數的作用:
e:/>set nls_lang=simplified chinese_china.zhs16gbke:/>sqlplus "/ as sysdba"sql*plus: release 9.2.0.4.0 - production on 星期六 11月 1 22:51:59 2003copyright (c) 1982, 2002, oracle corporation. all rights reserved.連接到:oracle9i enterprise edition release 9.2.0.4.0 - productionwith the partitioning, oracle label security, olap and oracle data mining optionsjserver release 9.2.0.4.0 - productionsql> select sysdate from dual;sysdate----------01-11月-03已選擇 1 行。sql> exit從oracle9i enterprise edition release 9.2.0.4.0 - productionwith the partitioning, oracle label security, olap and oracle data mining optionsjserver release 9.2.0.4.0 - production中斷開e:/>set nls_lang=american_america.zhs16gbke:/>sqlplus "/ as sysdba"sql*plus: release 9.2.0.4.0 - production on sat nov 1 22:52:24 2003copyright (c) 1982, 2002, oracle corporation. all rights reserved.connected to:oracle9i enterprise edition release 9.2.0.4.0 - productionwith the partitioning, oracle label security, olap and oracle data mining optionsjserver release 9.2.0.4.0 - productionsql> select sysdate from dual;sysdate---------01-nov-031 row selected.sql>
查看客戶端nls_lang設置可以使用以下方法:
windows使用:echo %nls_lang%如:e:/>echo %nls_lang%american_america.zhs16gbkunix使用:env|grep nls_lang如:/opt/oracle>env|grep nls_langnls_lang=american_china.zhs16gbkwindows客戶端設置,可以在注冊表中更改nls_lang,具體鍵值位于:hkey_local_machine oftware/oracle/homexx/xx指存在多個oracle_home時系統編號。
導入和導出是客戶端產品,同sql*plus和oralce forms一樣,因此,使用exp/imp工具將按照nls_lang定義的方式轉換字符集。
導出使用的字符集將會記錄在導出文件中,當文件導入時,將會檢查導出時使用的字符集設置,如果這個字符集不同于導入客戶端的nls_lang
設置,字符集將根據導入客戶端nls_lang設置進行轉換,如果必要,在數據插入數據庫之前會進行進一步轉換。
通常在導出時最好把客戶端字符集設置得和數據庫端相同,這樣可以避免在導出時發生不必要的數據轉換,導出文件將和數據庫具有相同的字符集。
即使將來會把導出文件導入到不同字符集的數據庫中,這樣做也可以把轉換延緩至導入時刻。
當進行數據導入時,主要存在以下兩種情況:
1.源數據庫和目標數據庫具有相同字符集設置
這時,只需要設置nls_lang等于數據庫字符集即可導入(前提是,導出使用的是和源數據庫相同字符集,即三者相同)
2.源數據庫和目標數據庫字符集不同
如果我們導出時候使用的nls_lang是和源數據庫相同的字符集,那么導入時就可以設置客戶端nls_lang等于導出時使用的字符集,這
樣轉換只發生在數據庫端,而且只發生一次。
例如:
如果進行從we8mswin1252到utf8的轉換
1)使用nls_lang=american_america.we8mswin1252導出數據庫。
這時創建的導出文件包含we8mswin1252的數據
2)導入時使用nls_lang=american_america.we8mswin1252
這時轉換僅發生在insert數據到utf8的數據庫中。
以上假設的轉換只在目標數據庫字符集是源數據庫字符集的超集時才能轉換。如果不同,一般就需要進行一些特殊的處理。
我們簡單看一下導入的轉換過程(以oracle8i為例):
1.確定導出數據庫字符集環境
通過讀取導出文件頭,可以獲得導出文件的字符集設置
2.確定導入session的字符集,即導入session使用的nls_lang環境變量
3.imp讀取導出文件
讀取導出文件字符集id,和導入進程的nls_lang進行比較
4.如果導出文件字符集和導入session字符集相同,那么在這一步驟內就不需要轉換
如果不同,就需要把數據轉換為導入session使用的字符集。
然而這種轉換只能在單byte字符集之間進行。
我們看一個測試:
e:/nls2>set nls_lang=american_america.us7ascii設置導入session nls_lang為us7asciie:/nls2>e:/oracle/ora8i/bin/imp eygle/eygle file=sus7ascii-cus7ascii-exp817.dmp fromuser=eygle touser=eygle tables=test這個導出文件是從us7ascii數據庫導出,導出客戶端nls_lang也是us7asciiimport: release 8.1.7.1.1 - production on fri nov 7 00:59:22 2003(c) copyright 2000 oracle corporation. all rights reserved.connected to: oracle8i enterprise edition release 8.1.7.1.1 - productionwith the partitioning optionjserver release 8.1.7.1.1 - production這時導入,在dmp文件和nls_lang之間不需要進行字符集轉換。export file created by export:v08.01.07 via conventional pathimport done in us7ascii character set and zhs16gbk nchar character setimport server uses zhs16gbk character set (possible charset conversion)export server uses utf8 nchar character set (possible ncharset conversion). . importing table "test" 2 rows importedimport terminated successfully without warnings.
5.對于多byte字符集的導入(如:utf8)
需要設置導入session字符集和導出字符集相同
否則就會遇到:imp-16 "required character set conversion (type %lu to %lu) not supported" 錯誤。
:
e:/nls2>set nls_lang=american_america.zhs16gbk導入session字符集設置為zhs16gbk導入us7ascii的導出文件e:/nls2>e:/oracle/ora8i/bin/imp eygle/eygle file=sus7ascii-cus7ascii-exp817.dmp fromuser=eygle touser=eygleimport: release 8.1.7.1.1 - production on fri nov 7 00:38:55 2003(c) copyright 2000 oracle corporation. all rights reserved.connected to: oracle8i enterprise edition release 8.1.7.1.1 - productionwith the partitioning optionjserver release 8.1.7.1.1 - productionimp-00016: required character set conversion (type 1 to 852) not supportedimp-00000: import terminated unsuccessfully在從導出文件us7ascii到導入 nls_lang設置為zhs16gbk的過程中,不支持單byte字符集向多byte轉換,報出以上錯誤。
6.導入session字符集應該是導出字符集的超級,否則,專有的字符將難以正確轉換。
7.當數據轉換為導入session字符集設置以后,如果導入session字符集不同于導入數據庫字符集,這時還需要最后一步轉換,這要求導入數據庫字符
集是導入session字符集的超級,否則某些專有字符將不能正常轉換。
我們繼續看上面的兩個過程,這里有這樣兩個原則:
1.如果nls_lang的設置和數據庫相同,那么數據(在傳輸過程中當然是2進制碼)不經過轉換就直接插入數據庫中。
2.如果nls_lang的設置和數據庫不同,那么數據需要轉換后才能插入數據庫中。
我們再回頭來看上面的第一個例子:
:
export file created by export:v08.01.07 via conventional pathimport done in us7ascii character set and zhs16gbk nchar character setimport server uses zhs16gbk character set (possible charset conversion)export server uses utf8 nchar character set (possible ncharset conversion). . importing table "test" 2 rows importedimport terminated successfully without warnings.這時候經過第一步轉換后的數據,us7ascii到zhs16gbk丟失首位,原樣插入數據庫,我們看到這時數據庫中存放的就是錯誤的字符(在后面
部分我們做了詳細的轉換):e:/nls2>sqlplus eygle/eyglesql*plus: release 9.2.0.4.0 - production on fri nov 7 00:35:39 2003copyright (c) 1982, 2002, oracle corporation. all rights reserved.connected to:oracle8i enterprise edition release 8.1.7.1.1 - productionwith the partitioning optionjserver release 8.1.7.1.1 - productionsql> select * from test;name--------------------2bjttest
在oracle9i中,以上情況略有不同。