關於字元集的一些問題:
博主最近開始學習oracle啦,不得不說oracle的內容真的太廣了,學好它不僅僅是資料庫本身的問題,好多時候會牽扯各種作業系統,記得剛剛在redhat下開始安裝oracle的時候差不多鼓搗了一天啊。OK,言歸正傳,最近博主在測試一些簡單的SQL語句時發現一個問題:
哇哦,這是什麼鬼,不能識別我大天朝的語言嗎。嚇得我趕快從網上查了查原因,貌似牽扯字元集的原因。其實很簡答啦,僅僅是在安裝資料庫的時候字元設定預設語言沒有選對。
(這裡字元集要解釋一下:字元集(也稱字元集,Character Set)就是字元編碼表(codepage),一個字元不論英文、中文、韓文等在電腦系統記憶體或硬碟中通過二進位的位元組(Byte)儲存,這個二進位的編碼就是字元編碼(也稱內碼),字元集就是字元與內碼的對應(映射)表。
因為多國語言的原因,就出現了根據本國語言製作的字元集。如使用最廣泛的ASCII編碼,由美國國家標準局(即ANSI)制定,適用於所有拉丁、英文字元。中國大陸使用GB2312,GBK,GB18030等字元集,這些字元集包含所有漢字字元的內碼,其中GBK,GB18030稱為大字元集,對繁體中文也進行了編碼。香港、台灣、澳門地區使用Big5編碼,Big5收錄了繁體中文(有些繁體與中國大陸繁體字元有差異)的編碼,不包含簡體中文的字元編碼。
本段話轉自:
http://www.cnblogs.com/zhwl/p/3745257.html)
utf-8:可變長度,當utf-8用來表示英文時,會直接使用一位位元組來表示,但是查詢漢字的時候可能使用多位位元組來表示
utf-16:固定長度,全部使用兩位位元組來表示,這樣的話表示英文會很占空間,但是讀起來會更快
上圖中database character set 即為資料庫字元集的設定(要注意,以上為伺服器端的字元集設定。用戶端的字元集則是在使用者的環境變數中),若使用預設的話,若插入資料庫漢字,查詢時會出現亂碼的情況(原因見後面描述)。這裡的選項為包含所有漢字字元的GBK字元集。
characterset:控制用戶端應用程式使用的字元集。最後一個選項defult territory也好理解,這個是選擇的地區,會對貨幣和數字格式,地區和計算星期及日期的習慣等有影響,而defualt language 有什麼作用呢。它其實是對Oracle訊息使用的語言,日期中月份和日顯示有影響的。
服務端字元集的構成體現在資料字典表V$NLS_PARAMETERS的NLS_LANGUAGE、NLS_TERRITORY、NLS_CHARACTERSET三項取值上,其中NLS_CHARACTERSET的取值就是具體的資料庫字元集。如利用查詢語句SQL>SELECT * FROM V$NLS_PARAMETERS;可得到如下結果:
PARAMETER VALUE
NLS_LANGUAGE SIMPLIFIED CHINESE
NLS_TERRITORY CHINA
NLS_CHARACTERSET ZHS16GBK
即當前資料庫使用的字元集是ZHS16GBK。
Ps:根據ORACLE官方文檔的說明,一旦資料庫建立後,資料庫的字元集是不能改變的。資料庫服務端的字元集是在建立資料時設定的。但可通過如下方法對已設定的字元集進行修改:
方法一:重建資料庫。建立資料庫時將資料庫的字元集設定為所需字元集。
方法二:修改SYS.PROPS$表。即用SYS使用者登陸ORACLE後,利用下面語句修改相應的字元集並提交:SQL>UPDATE PROPS$ SET VALUE$=’ZHS16GBK‘WHERE NAME=’NLS_CHARACTERSET’;SQL>COMMIT;通過此種方法來更改資料庫字元集,只對更改後的資料有效,即資料庫中原來的資料仍以原字元集被儲存。【很野的路子。改的是oracle的基表】
在SQL語句中可以使用:SQL>select userenv (‘language’) from dual;
來查詢,比如,
查詢用戶端字元集:$echo $NLS_LANG $env | grep NLS_LANG
1、可以在.bash_profile 檔案中添加:export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK的方法來更改(永久設定 instance層級。)
2、alter session set nls_language='american' nls_territory='america';
alter session set nls_language='american';
alter session set nls_territory='america';(session層級)
作業系統字元集:
查看:echo $LANG / env | grep LANG
GDM - The GNOME Display Manager
G:圖形 D:案頭 M:管理器
1、直接設定變數的方式修改,命令如下兩條命令:
[root@david ~]# LANG=xxx 或者 export LANG=xxx;
[root@david ~]# LC_ALL=”xxx” 或者 export LC_ALL=”xxx”;
2、修改檔案方式,通過修改/etc/sysconfig/i18n檔案控制
[root@david ~]# vim /etc/sysconfig/i18n
LANG="zh_CN.GB18030" 即為系統的語言
SUPPORTED="zh_CN.UTF-8:zh_CN.GB18030:zh_CN:zh:en_US.UTF-8:en_US:en"
SYSFONT="lat0-sun16"
修改檔案儲存退出之後要生效要執行如下命令才可生效
[test@pan ~]$ source /etc/sysconfig/i18n
問題:
如果作業系統字元集與用戶端字元集不一致會怎麼樣。
通過SQL> select userenv ('language') from dual;查詢出USERENV('LANGUAGE')AMERICAN_AMERICA.ZHS16GBK其中AMERICAN_AMERICA是和當前session同一水平的嗎(保持一致)。還是只與sever端有關係。
可以在.bash_profile 檔案中添加:EXPORT NLS_LANG=AMERICAN_AMERICA.ZHS16GBK 是對instance層級用戶端字元集的更改嗎。
亂碼的真正原因:
NLS( National Language Support)國家語言支援。NLS是資料庫的一個非常強大的特性,它控制著資料的許多方面:比如資料如何儲存,一般來說它控制著以下兩個方面:
1、文本資料持久儲存在磁碟上時如何編碼
2、透明的將資料從一個字元集轉換到另外一個字元集。
假設你在資料庫中用WE8ISO8859P1 字元集儲存8 位的資料,但是你的某些客戶使用的是一種7位字元集,如US7ASCII字元集轉換過程通常會修改資料,而你往往會把一個較大的字元集(在此例中就是8位字元集)映射到一個較小的字元集(此例中的7位字元集)。這是一種有損轉換(lossy conversion),字元就會被修改,這隻是因為:較小的字元集不可能表示較大字元集中的每一個字元。但是這種轉換必鬚髮生。這也是亂碼產生的原因。如果資料庫以一種單一位元組字元集儲存資料,但是客戶(如一個Java應用,因為Java語言使用Unicode)希望資料採用多位元組表示,就必須執行轉換,只有這樣客戶應用才能使用這些資料。(http://www.cnblogs.com/kerrycode/p/3749085.html)
參考文獻:
http://blog.itpub.net/29519108/viewspace-1298298/(大部分是英文文獻)
http://www.cnblogs.com/kerrycode/p/3749085.html(基礎概念描述)
http://www.cnblogs.com/zhwl/p/3745257.html(oracle資料庫文字儲存解決方案,很詳細的中文文獻)
http://blog.csdn.net/jovitang/article/details/5174062(一位技術達人的總結)