oracle查询本身字符集,Oracle字符集问题总结
有過一些Oracle使用經驗的朋友,大多會知道通過NLS_LANG來設置客戶端的情況,NLS_LANG由以下部分組成:NLS_LANG=_.,其中第三部分的本意就是用來指明客戶端操作系統缺省使用的字符集。所以按正規的用法,NLS_LANG應該按照客戶端機器的實際情況進行配置,尤其對于字符集一項更是如此,這樣Oracle就能夠在最大程度上實現數據庫字符集與客戶端字符集的自動轉換(當然是如果需要轉換的話)。總結一下第一次迭代的重點:字符集:將特定的符號集編碼為計算機能夠處理的數值;字符集間的轉換:對于在源字符集與目標字符集都存在的符號,理論上轉換將不會產生信息丟失;而對于在源字符集中存在而在目標字符集中不存在的符號,理論上轉換將會產生信息丟失;數據庫字符集:選擇能夠包含所有將要存儲的信息符號的字符集;客戶端字符集設置:指明客戶端操作系統缺省使用的字符集。第二次迭代:通過實例加深對基本概念的理解下面我將引用網友tellin在ITPUB上發表的“CHARACTER SET研究及疑問”帖子,該朋友在帖子中列舉了他做的相關實驗,并對實驗結果提出了一些疑問,我將對他的實驗結果進行分析,并回答他的疑問。實驗結果分析一quote:--------------------------------------------------------------------------------最初由 tellin 發布設置客戶端字符集為US7ASCIID:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII查看服務器字符集為US7ASCIISQL> SELECT * FROM NLS_DATABASE_PARAMETERS;PARAMETER VALUE------------------------------ ----------------------------------------NLS_CHARACTERSET US7ASCII建立測試表SQL> CREATE TABLE TEST (R1 VARCHAR2(10));Table created.插入數據SQL> INSERT INTO TEST VALUES('東北');1 row created.SQL> SELECT * FROM TEST;R1----------東北SQL> EXIT--------------------------------------------------------------------------------這一部分的實驗數據的存取與顯示都正確,好象沒什么問題,但實際上卻隱藏著很大的隱患。首先,要將漢字存入數據庫,而將數據庫字符集設置為US7ASCII是不合適的。US7ASCII字符集只定義了128個符號,并不支持漢字。另外,由于在SQL*PLUS中能夠輸入中文,操作系統缺省應該是支持中文的,但在NLS_LANG中的字符集設置為US7ASCII,顯然也是不正確的,它沒有反映客戶端的實際情況。但實際顯示卻是正確的,這主要是因為Oracle檢查數據庫與客戶端的字符集設置是同樣的,那么數據在客戶與數據庫之間的存取過程中將不發生任何轉換。具體地說,在客戶端輸入“東北”,“東”的漢字的編碼為182(10110110)、171(10101011),“北”漢字的編碼為177(10110001)、177(10110001),它們將不做任何變化的存入數據庫中,但是這實際上導致了數據庫標識的字符集與實際存入的內容是不相符的,從某種意義上講,這也是一種不一致性,也是一種錯誤。而在SELECT的過程中,Oracle同樣檢查發現數據庫與客戶端的字符集設置是相同的,所以它也將存入的內容原封不動地傳送到客戶端,而客戶端操作系統識別出這是漢字編碼所以能夠正確顯示。在這個例子中,數據庫與客戶端的設置都有問題,但卻好象起到了“負負得正”的效果,從應用的角度看倒好象沒問題。但這里面卻存在著極大的隱患,比如在應用length或substr等字符串函數時,就可能得到意外的結果。另外,如果遇到導入/導出(import /export)將會遇到更大的麻煩。有些朋友在這方面做了大量的測試,如eygle研究了“源數據庫字符集為US7ASCII,導出文件字符集為US7ASCII或ZHS16GBK,目標數據庫字符集為ZHS16GBK”的情況,他得出的結論是 “如果的是在Oracle92中,我們發現對于這種情況,不論怎樣處理,這個導出文件都無法正確導入到Oracle9i數據庫中”、“對于這種情況,我們可以通過使用Oracle8i的導出工具,設置導出字符集為US7ASCII,導出后修改第二、三字符,修改 0001 為0354,這樣就可以將US7ASCII字符集的數據正確導入到ZHS16GBK的數據庫中”。我想對于這些結論,這樣理解可能更合適一些:由于ZHS16GBK字符集是US7ASCII的超級,所以如果按正常操作,這種轉換應該沒有問題;但出現問題的本質是我們讓本應只存儲英文字符的US7ASCII數據庫,非常規地存儲了中文信息,那么在轉化過程中出現錯誤或麻煩就沒什么奇怪的了,不出麻煩倒是有些奇怪了。所以說要避免這種情況,就是要在建立數據庫時選擇合適的字符集,不讓標簽(數據庫的字符集設置)與實際(數據庫中實際存儲的信息)不符的情況發生。實驗結果分析二quote:--------------------------------------------------------------------------------[ 更改客戶端字符集為ZHS16GBKD:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBKD:\>SQLPLUS "/ AS SYSDBA"無法正常顯示數據SQL> SELECT * FROM TEST;R1--------------------6+11疑問1:ZHS16GBK為US7ASCII的超集,為什么在ZHS16GBK環境下無法正常顯示--------------------------------------------------------------------------------這主要是因為Oracle檢查發現數據庫設置的字符集與客戶端配置字符集不同,它將對數據進行字符集的轉換。數據庫中實際存放的數據為182(10110110)、171(10101011)、177(10110001)、177(10110001),由于數據庫字符集設置為US7ASCII,它是一個7bit的字符集,存儲在8bit的字節中,則Oracle忽略各字節的最高bit,則182(10110110)就變成了54(0110110),在ZHS16GBK中代表數字符號“6”(當然在其它字符集中也是“6”),同樣過程也發生在其它3個字節,這樣“東北”就變成了“6+11”。實驗結果分析三quote:--------------------------------------------------------------------------------最初由 tellin 發布用ZHS16GBK插入數據SQL> INSERT INTO TEST VALUES('東北');1 row created.SQL> SELECT * FROM TEST;R1--------------------6+11??SQL> EXIT--------------------------------------------------------------------------------當客戶端字符集設置為ZHS16GBK后向數據庫插入“東北”,Oracle檢查發現數據庫設置的字符集為US7ASCII與客戶端不一致,需要進行轉換,但字符集ZHS16GBK中的“東北”兩字在US7ASCII中沒有對應的字符,所以Oracle用統一的“替換字符”插入數據庫,在這里為“?”,編碼為63(00111111),這時,輸入的信息實際上已經丟失,不管字符集設置如何改變(如下面引用的實驗結果),第二行SELECT出來的結果也都是兩個“?”號(注意是2個,而不是4個)。quote:--------------------------------------------------------------------------------更改客戶端字符集為US7ASCIID:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCIID:\>SQLPLUS "/ AS SYSDBA"無法顯示用ZHS16GBK插入的字符集,但可以顯示用US7ASCII插入的字符集SQL> SELECT * FROM TEST;R1----------東北??更改服務器字符集為ZHS16GBKSQL> update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';1 row updated.SQL> COMMIT;更改客戶端字符集為ZHS16GBKD:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBKD:\>SQLPLUS "/ AS SYSDBA"可以顯示以前US7ASCII的字符集,但無法顯示用ZHS16GBK插入的數據,說明用ZHS16GBK插入的數據為亂碼。SQL> SELECT * FROM TEST;R1--------------------東北??--------------------------------------------------------------------------------需要指出的是,通過“update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';”來修改數據庫字符集是非常規作法,很可能引起問題,在這里只是原文引用網友的實驗結果。
總結
以上是生活随笔為你收集整理的oracle查询本身字符集,Oracle字符集问题总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 奇妙的安全旅行之加密算法(完整版)
- 下一篇: AutoML 与 Bayesian Op