這是由於oracle資料庫服務端的字串為ZHS16GBK,而navicat並不支援。解決辦法是:修改oracle服務端的字元集,以sysdba角色登入oracle資料庫,修改props$系統資料表(oracle維護的表)的NLS_CHARACTERSET和NLS_NCHAR_CHARACTERSET,sql語句如下:
update props$ set value$='AL32UTF8' where name='NLS_CHARACTERSET' or name='NLS_NCHAR_CHARACTERSET';
SQL> update props$ set value$='AL32UTF8' where name='NLS_CHARACTERSET' or name='NLS_NCHAR_CHARACTERSET';
2 rows updated
最後重啟電腦。
再次開機可能會出現TNS無法啟動,如果手動啟動會提示如下錯誤:
本機電腦上的OracleOraDb10g_home1TNSListener服務啟動後又停止了..........解決辦法:
http://blog.csdn.net/centre10/archive/2010/12/07/6060828.aspx
服務端字元集:NLS_CHARACTERSET和NLS_NCHAR_CHARACTERSET
用戶端字元集:windows下:在註冊表中找,同時修改NLS_LANG linux下:profile或者修改.bash_profile
備份檔案字元集:先備份一個資料庫表,找到第2和3個資料,如:0369用相關命令得到其字元集。
下面這篇文章會有用。
一.oracle字元集:
Oracle字元集是一個位元組資料的解釋的符號集合,有大小之分,有相互的包容關係。ORACLE 支援國家語言的體繫結構允許你使用本地化語言來儲存,處理,檢索資料。它使資料庫工具,錯誤訊息,排序次序,日期,時間,貨幣,數字,和日曆自動適應本地化語言和平台。
影響oracle資料庫字元集最重要的參數是NLS_LANG參數。
它的格式如下: NLS_LANG = language_territory.charset
它有三個組成部分(語言、地區和字元集),每個成分控制了NLS子集的特性。
其中:
Language 指定伺服器訊息的語言,territory 指定伺服器的日期和數字格式,charset 指定字元集。如:AMERICAN _ AMERICA. ZHS16GBK ;AMERICAN _ AMERICA.AL32UTF8
從NLS_LANG的組成我們可以看出,真正影響資料庫字元集的其實是第三部分。
所以兩個資料庫之間的字元集只要第三部分一樣就可以相互匯入匯出資料,前面影響的只是提示資訊是中文還是英文。
二.查看資料庫字元集
這涉及三方面的字元集,
一是oracel server端的字元集;
二是oracle client端的字元集;
三是dmp檔案的字元集。
在做資料匯入的時候,需要這三個字元集都一致才能正確匯入。
1、查詢oracle server端的字元集
有很多種方法可以查出oracle server端的字元集,比較直觀的查詢方法是以下這種:
SQL>select userenv('language') from dual;
結果類似如下:AMERICAN _ AMERICA. ZHS16GBK
2、如何查詢dmp檔案的字元集
exp命令備份資料庫
到oracle的bin目錄下:cd c:/oracle/bin(oracle的安裝目錄)
exp userid=scott/centre@orcl tables=(emp) file=d:/emp.dmp(備份單張表)
exp userid=scott/centre@orcl tables=(emp,dept) file=d:/emp1.dmp(備份多張表)
exp userid=scott/centre@orcl tables=(emp) file=d:/emp3.dmp rows=n(備份表的結構)
exp userid=scott/centre@orcl tables=(emp) file=d:/emp2.dmp direct=y(直接匯出)
exp userid=scott/centre@orcl owner=scott file=d:/scott.dmp(備份自己的解決方案)
exp userid=system/centre@orcl owner=(system,scott) file=d:/system.dmp(備份任何解決方案)
imp命令還原資料庫
imp userid=scott/centre@orcl tables=(emp) file=d:/xx.dmp(匯入自己表)
imp userid=system/centre@orcl tables=(emp) file=d:/xx.dmp touser=scott(匯入到別人的表)
imp userid=scott/centre@orcl tables=(emp) file=d:/emp3.dmp rows=n(匯入表結構而不匯入資料)
........
用oracle的exp工具匯出的dmp檔案也包含了字元集資訊,dmp檔案的第2和第3個位元組記錄了dmp檔案的字元集。如果dmp檔案不大,比如只有幾M或幾十M,可以用UltraEdit開啟(16進位方式),看第2第3個位元組的內容,如0354,然後用以下SQL查出它對應的字元集:
SQL> select nls_charset_name(to_number('0369','xxxx')) from dual;
AL32UTF8
如果dmp檔案很大,比如有2G以上(這也是最常見的情況),用文字編輯器開啟很慢或者完全打不開,可以用以下命令(在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端相同的字元集。
補充:
(1).資料庫伺服器字元集環境
select * from nls_database_parameters;
來源於props$,是表示資料庫的字元集。
(2).用戶端字元集環境
select * from nls_instance_parameters ;
其來源於v$parameter,表示用戶端的字元集的設定,可能是參數檔案,環境變數或者是註冊表
(3).會話字元集環境
select * from nls_session_parameters;
來源於v$nls_parameters,表示會話自己的設定,可能是會話的環境變數或者是alter session完成,如果會話沒有特殊的設定,將與nls_instance_parameters一致。
(4).用戶端的字元集要求與伺服器一致,才能正確顯示資料庫的非Ascii字元。如果多個設定存在的時候,alter session>環境變數>註冊表>參數檔案
字元集要求一致,但是語言設定卻可以不同,語言設定建議用英文。如字元集是zhs16gbk,則nls_lang可以是American_America.zhs16gbk。
三、修改oracle的字元集
上文說過,oracle的字元集有互相的包容關係。如us7ascii就是zhs16gbk的子集,從us7ascii到zhs16gbk不會有資料解釋上的問題,不會有資料丟失。在所有的字元集中utf8應該是最大,因為它基於unicode,雙位元組儲存字元(也因此在儲存空間上佔用更多)。
一旦資料庫建立後,資料庫的字元集理論上講是不能改變的。因此,在設計和安裝之初考慮使用哪一種字元集十分重要。根據Oracle的官方說明,字元集的轉換是從子集到超集受支援,反之不行。如果兩種字元集之間根本沒有子集和超集的關係,那麼字元集的轉換是不受oracle支援的。對資料庫server而言,錯誤的修改字元集將會導致很多不可測的後果,可能會嚴重影響資料庫的正常運行,所以在修改之前一定要確認兩種字元集是否存在子集和超集的關係。一般來說,除非萬不得已,我們不建議修改oracle資料庫server端的字元集。特別說明,我們最常用的兩種字元集ZHS16GBK和ZHS16CGB231280之間不存在子集和超集關係,因此理論上講這兩種字元集之間的相互轉換不受支援。
1、修改server端字元集(不建議使用)
在oracle 8之前,可以用直接修改資料字典表props$來改變資料庫的字元集。但oracle8之後,至少有三張系統資料表記錄了資料庫字元集的資訊,只改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
注意:如果沒有大對象,在使用過程中進行語言轉換沒有什麼影響,(切記設定的字元集必須是ORACLE支援,不然不能start) 按上面的做法就可以,但是可能會出現‘ORA-12717: Cannot ALTER DATABASE NATIONAL CHARACTER SET when NCLOB data exists’ 這樣的提示資訊
要解決這個問題有兩種方法
一個是,利用INTERNAL_USE 關鍵字修改地區設定,
還有一個是利用re-create,但是re-create有點複雜,所以請用internal_use,
SQL>SHUTDOWN IMMEDIATE;
SQL>STARTUP MOUNT EXCLUSIVE;
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 NATIONAL CHARACTER SET INTERNAL_USE UTF8;
SQL>SHUTDOWN immediate;
SQL>startup;
如果按上面的做法做,National charset的地區設定就沒有問題
2、修改dmp檔案字元集
上文說過,dmp檔案的第2第3位元組記錄了字元集資訊,因此直接修改dmp檔案的第2第3位元組的內容就可以‘騙’過oracle的檢查。這樣做理論上也僅是從子集到超集可以修改,但很多情況下在沒有子集和超集關係的情況下也可以修改,我們常用的一些字元集,如US7ASCII,WE8ISO8859P1,ZHS16CGB231280,ZHS16GBK基本都可以改。因為改的只是dmp檔案,所以影響不大。
具體的修改方法比較多,最簡單的就是直接用UltraEdit修改dmp檔案的1和2個位元組。
比如想將dmp檔案的字元集改為ZHS16GBK,可以用以下SQL查出該種字元集對應的16進位代碼:
SQL> select to_char(nls_charset_id('ZHS16GBK'), 'xxxx') from dual;
0354
然後將dmp檔案的2、3位元組修改為0354即可。
如果dmp檔案很大,用ue無法開啟,就需要用程式的方法了
Oracle修改字元集
2.3oracle資料庫的字元集更改
A、oracle server 端 字元集查詢
select userenv('language') from dual
其中NLS_CHARACTERSET 為server端字元集
NLS_LANGUAGE 為 server端字元顯示形式
B、查詢oracle client端的字元集
$echo $NLS_LANG
如果發現你select 出來的資料是亂碼,請把client端的字元集配置成與linux作業系統相同的字元集。如果還是有亂碼,則有可能是資料庫中的資料存在問題,或者是oracle服務端的配置存在問題。
C、server端字元集修改
*****************************************************************
* 更改字元集步驟方法(WE8ISO8859P1 --> ZHS16GBK) *
*****************************************************************
SQL>
將資料庫啟動到RESTRICTED模式下做字元集更改:
SQL> conn /as sysdba
Connected.
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount
ORACLE instance started.
Total System Global Area 236000356 bytes
Fixed Size 451684 bytes
Variable Size 201326592 bytes
Database Buffers 33554432 bytes
Redo Buffers 667648 bytes
Database mounted.
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
System altered.
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
System altered.
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
System altered.
SQL> alter database open;
Database altered.
SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;
ALTER DATABASE CHARACTER SET ZHS16GBK
*
ERROR at line 1:
ORA-12712: new character set must be a superset of old character set
提示我們的字元集:新字元集必須為舊字元集的超集,這時我們可以跳過超集的檢查做更改:
SQL> ALTER DATABASE character set INTERNAL_USE ZHS16GBK;
Database altered.
SQL> select * from v$nls_parameters;
略
19 rows selected.
重啟檢查是否更改完成:
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 236000356 bytes
Fixed Size 451684 bytes
Variable Size 201326592 bytes
Database Buffers 33554432 bytes
Redo Buffers 667648 bytes
Database mounted.
Database opened.
SQL> select * from v$nls_parameters;
略
19 rows selected.
我們看到這個過程和之前ALTER DATABASE CHARACTER SET操作的內部過程是完全相同的,也就是說INTERNAL_USE提供的協助就是使
Oracle資料庫繞過了子集與超集的校正.
這一方法在某些方面是有用處的,比如測試;應用於產品環境大家應該格外小心,除了你以外,沒有人會為此帶來的後果負責:
結語(我們不妨再說一次):
對於DBA來說,有一個很重要的原則就是:不要把你的資料庫置於危險的境地!
這就要求我們,在進行任何可能對資料庫結構發生改變的操作之前,先做有效備份,很多DBA沒有備份的操作中得到了慘痛的教訓
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
D、client端字元集修改
在 /home/oracle與 /root使用者目錄下的.bash_profile中
添加或修改 export NLS_LANG="AMERICAN_AMERICA.UTF8" 語句
關閉當前ssh視窗。
注意 NLS_LANG變數一定要配置正確否則會引起sqlplus 失效