Oracle 字符集問題

1 簡介 ORACLE數據庫字符集,即Oracle全球化支持(Globalization Support),或即國家語言支持(NLS)其做用是用本國語言和格式來存儲、處理和檢索數據。利用全球化支持,ORACLE爲用戶提供本身熟悉的數據庫母語環境,諸如日期格式、數字格式和存儲序列等。Oracle能夠支持多種語言及字符集,其中oracle8i支持48種語言、76個國家地域、229種字符集,而oracle9i則支持57種語言、88個國家地域、235種字符集。因爲oracle字符集種類多,且在存儲、檢索、遷移Oracle數據時多個環節與字符集的設置密切相關,所以在實際的應用中,數據庫開發和管理人員常常會遇到有關oracle字符集方面的問題。本文經過如下幾個方面闡述,對oracle字符集作簡要分析 2 字符集基本知識 2.1字符集 實質就是按照必定的字符編碼方案,對一組特定的符號,分別賦予不一樣數值編碼的集合,是各個字符的一種二進制表示(用位和字節表示)。目前有多種不一樣的字符集,每種字符集能表示不一樣的字符。Oracle數據庫最先支持的編碼方案是US7ASCII。 Oracle的字符集命名遵循如下命名規則: 即: <語言><比特位數><編碼> 好比: ZHS16GBK表示採用GBK編碼格式、16位(兩個字節)簡體中文字符集 2.2字符編碼方案 2.2.1單字節編碼 (1)單字節7位字符集,能夠定義128個字符,最經常使用的字符集爲US7ASCII (2)單字節8位字符集,能夠定義256個字符,適合於歐洲大部分國家 例如:WE8ISO8859P1(西歐、8位、ISO標準8859P1編碼) 2.2.2 多字節編碼 (1)變長多字節編碼 某些字符用一個字節表示,其它字符用兩個或多個字符表示,變長多字節編碼經常使用於對亞洲語言的支持, 例如日語、漢語、印地語等 例如:AL32UTF8(其中AL表明ALL,指適用於全部語言)、zhs16cgb231280 (2)定長多字節編碼 每個字符都使用固定長度字節的編碼方案,目前oracle惟一支持的定長多字節編碼是AF16UTF16,也是僅用於國家字符集 2.2.3 Unicode編碼 Unicode是一個涵蓋了目前全世界使用的全部已知字符的單一編碼方案,也就是說Unicode爲每個字符提供惟一的編碼。UTF-16是Unicode的16位編碼方式,是一種定長多字節編碼,用2個字節表示一個Unicode字符,AF16UTF16是UTF-16編碼字符集。 UTF-8是Unicode的8位編碼方式,是一種變長多字節編碼,這種編碼能夠用一、二、3個字節表示一個Unicode字符,AL32UTF8,UTF八、UTFE是UTF-8編碼字符集 2.3 字符集超級 當一種字符集(字符集A)的編碼數值包含全部另外一種字符集(字符集B)的編碼數值,而且兩種字符集相同編碼數值表明相同的字符時,則字符集A是字符集B的超級,或稱字符集B是字符集A的子集。 Oracle8i和oracle9i官方文檔資料中備有子集-超級對照表(subset-superset pairs),例如:WE8ISO8859P1是WE8MSWIN1252的子集。因爲US7ASCII是最先的Oracle數據庫編碼格式,所以有許多字符集是US7ASCII的超集,例如WE8ISO8859P一、ZHS16CGB231280、ZHS16GBK都是US7ASCII的超集。 2.4 數據庫字符集(oracle服務器端字符集) 數據庫字符集在建立數據庫時指定,在建立後一般不能更改。在建立數據庫時,能夠指定字符集(CHARACTER SET)和國家字符集(NATIONAL CHARACTER SET)。 2.4.1字符集 (1)用來存儲CHAR, VARCHAR2, CLOB, LONG等類型數據 (2)用來標示諸如表名、列名以及PL/SQL變量等 (3)用來存儲SQL和PL/SQL程序單元等 2.4.2國家字符集: (1)用以存儲NCHAR, NVARCHAR2, NCLOB等類型數據 (2)國家字符集實質上是爲oracle選擇的附加字符集,主要做用是爲了加強oracle的字符處理能力,由於NCHAR數據類型能夠提供對亞洲使用定長多字節編碼的支持,而數據庫字符集則不能。國家字符集在oracle9i中進行了從新定義,只能在Unicode編碼中的AF16UTF16和UTF8中選擇,默認值是AF16UTF16 2.4.3查詢字符集參數 能夠查詢如下數據字典或視圖查看字符集設置狀況 nls_database_parameters、props$、v$nls_parameters 查詢結果中NLS_CHARACTERSET表示字符集,NLS_NCHAR_CHARACTERSET表示國家字符集 2.4.4修改數據庫字符集 按照上文所說,數據庫字符集在建立後原則上不能更改。若是須要修改字符集,一般須要導出數據庫數據,重建數據庫,再導入數據庫數據的方式來轉換,或經過ALTER DATABASE CHARACTER SET語句修改字符集,但建立數據庫後修改字符集是有限制的,只有新的字符集是當前字符集的超集時才能修改數據庫字符集,例如UTF8是US7ASCII的超集,修改數據庫字符集可以使用ALTER DATABASE CHARACTER SET UTF8。 2.5 客戶端字符集(NLS_LANG參數) 2.5.1客戶端字符集含義 客戶端字符集定義了客戶端字符數據的編碼方式,任何發自或發往客戶端的字符數據均使用客戶端定義的字符集編碼,客戶端能夠看做是能與數據庫直接鏈接的各類應用,例如sqlplus,exp/imp等。客戶端字符集是經過設置NLS_LANG參數來設定的。 2.5.2 NLS_LANG參數格式 NLS_LANG=_. Language:顯示oracle消息,校驗,日期命名 Territory:指定默認日期、數字、貨幣等格式 Client character set:指定客戶端將使用的字符集 例如:NLS_LANG=AMERICAN_AMERICA.US7ASCII AMERICAN是語言,AMERICA是地區,US7ASCII是客戶端字符集 2.5.3客戶端字符集設置方法 1)UNIX環境 $NLS_LANG=「simplified chinese」_china.zhs16gbk $export NLS_LANG 編輯oracle用戶的profile文件 2)Windows環境 編輯註冊表 Regedit.exe---HKEY_LOCAL_MACHINE---SOFTWARE---ORACLE—HOME 2.5.4 NLS參數查詢 Oracle提供若干NLS參數定製數據庫和用戶機以適應本地格式,例若有NLS_LANGUAGE,NLS_DATE_FORMAT,NLS_CALENDER等,能夠經過查詢如下數據字典或v$視圖查看。 NLS_DATABASE_PARAMETERS--顯示數據庫當前NLS參數取值,包括數據庫字符集取值 NLS_SESSION_PARAMETERS--顯示由NLS_LANG 設置的參數,或通過alter session 改變後的參數值(不包括由NLS_LANG 設置的客戶端字符集) NLS_INSTANCE_PARAMETE--顯示由參數文件init.ora 定義的參數V$NLS_PARAMETERS--顯示數據庫當前NLS參數取值 2.5.5修改NLS參數 使用下列方法能夠修改NLS參數 (1)修改實例啓動時使用的初始化參數文件 (2)修改環境變量NLS_LANG (3)使用ALTER SESSION語句,在oracle會話中修改 (4)使用某些SQL函數 NLS做用優先級別:Sql function>alter session>環境變量或註冊表>參數文件>數據庫默認參數 3 亂碼問題 Oracle在數據存儲、遷移過程當中常常發生字符亂碼問題,歸根究竟是因爲字符集使用不當引發。下面以使用客戶端sqlplus向數據庫插入數據爲例,說明亂碼產生的緣由。 3.1使用客戶端sqlplus向數據庫存儲數據 這個過程存在3個字符集設置 (1)客戶端應用字符集 (2)客戶端NLS_LANG參數設置 (3)服務器端數據庫字符集(Character Set)設置 客戶端應用Sqlplus中可以顯示什麼樣的字符取決於客戶端操做系統語言環境(客戶端應用字符集),但在應用中錄入這些字符後,這些字符可否在數據庫中正常存儲,還與另外兩個字符集設置緊密相關,其中客戶端NLS_LANG參數主要用於字符數據傳輸過程當中的轉換判斷。常見的亂碼大體有兩種情形: (1)漢字變成問號「?」; 當從字符集A 轉換成字符集B時,若是轉換字符之間不存在對應關係,NLS_LANG使用替代字符「?」替代沒法映射的字符 (2)漢字變成未知字符(雖然有些是漢字,但與原字符含義不一樣) 轉換存在對應關係,但字符集A 中的字符編碼與字符集B 中的字符編碼表明不一樣含義 3.2發生亂碼緣由 亂碼產生是因爲幾個字符集之間轉換不匹配形成,分如下幾種狀況: (注:字符集之間若是不存在子集、超集對應關係時的狀況不予考慮,由於這種狀況下字符集之間轉換必產生亂碼) 1)服務器端數據庫字符集與客戶端應用字符集相同,與客戶端NLS_LANG參數設置不一樣 若是客戶端NLS_LANG字符集是其它兩種字符集的子集,轉換過程將出現亂碼。 解決方法:將三種字符集設置成同一字符集,或NLS_LANG字符集是其它兩種字符集的超集 2)服務器端數據庫字符集與客戶端NLS_LANG參數設置相同,與客戶端應用字符集不一樣 若是客戶端應用字符集是其它兩種字符集的超集時,轉換過程將出現亂碼,但對於單字節編碼存儲中文問題,可參看本文第5章節的分析 3)客戶端應用字符集、客戶端NLS_LANG參數設置、服務器端數據庫字符集互不相同 此種狀況較爲複雜,但三種字符集之間只要有不能轉換的字符,則必產生亂碼 4 單字節編碼存儲中文問題 因爲歷史的緣由,早期的oracle沒有中文字符集(如oracle六、oracle七、oracle7.1),但有的用戶從那時起就使用數據庫了,並用US7ASCII字符集存儲了中文,或是有的用戶在建立數據庫時,不考慮清楚,隨意選擇一個默認的字符集,如WE8ISO8859P1或US7ASCII,而這兩個字符集都沒有漢字編碼,雖然有些時候選用這種字符集好象也能正常使用,但用這種字符集存儲漢字信息從原則上說就是錯誤的,它會給數據庫的使用與維護帶來一系列的麻煩。 正常狀況下,要將漢字存入數據庫,數據庫字符集必須支持中文,而將數據庫字符集設置爲US7ASCII等單字節字符集是不合適的。US7ASCII字符集只定義了128個符號,並不支持漢字。另外,若是在SQL*PLUS中可以輸入中文,操做系統缺省應該是支持中文的,但若是在NLS_LANG中的字符集設置爲US7ASCII,顯然也是不正確的,它沒有反映客戶端的實際狀況。但在實際應用中漢字顯示倒是正確的,這主要是由於Oracle檢查數據庫與客戶端的字符集設置是一樣的,那麼數據在客戶與數據庫之間的存取過程當中將不發生任何轉換,可是這實際上致使了數據庫標識的字符集與實際存入的內容是不相符的。而在SELECT的過程當中,Oracle一樣檢查發現數據庫與客戶端的字符集設置是相同的,因此它也將存入的內容原封不動地傳送到客戶端,而客戶端操做系統識別出這是漢字編碼因此可以正確顯示。 在這個例子中,數據庫與客戶端都沒有設置成中文字符集,但卻能正常顯示中文,從應用的角度看好象沒問題。然而這裏面卻存在着極大的隱患,好比在應用length或substr等字符串函數時,就可能獲得意外的結果。 對於早期使用US7ASCII字符集數據庫的數據遷移到oracle8i/9i中(使用zhs16gbk),因爲原始數據已經按照US7ASCII格式存儲,對於這種狀況,能夠經過使用Oracle8i的導出工具,設置導出字符集爲US7ASCII,導出後使用UltraEdit等工具打開dmp文件,修改第2、三字符,修改 0001 爲0354,這樣就能夠將US7ASCII字符集的數據正確導入到ZHS16GBK的數據庫中。 爲了不在數據庫遷移過程當中因爲字符集不一樣致使的數據損失,oracle提供了字符集掃描工具(character set scanner),經過這個工具咱們能夠測試在數據遷移過程當中因爲字符集轉換可能帶來的問題,而後根據測試結果,肯定數據遷移過程當中最佳字符集解決方案。 5 Oracle數據庫字符集問題解析 5.1字符集的概念。 咱們知道,電子計算機最初是用來進行科學計算的(因此叫作「計算機」),但隨着技術的發展,還須要計算機進行其它方面的應用處理。這就要求計算機不只能處理數值,還能處理諸如文字、特殊符號等其它信息,而計算機自己能直接處理的只有數值信息,因此就要求對這些文字、符號信息進行數值編碼,最初的字符集是咱們都很是熟悉的ASCII,它是用7個二進制位來表示128個字符,然後來隨着不一樣國家、組織的須要,出現了許許多多的字符集,如表示西歐字符的ISO8859系列的字符集,表示漢字的GB2312-80、GBK等字符集。 字符集的實質就是對一組特定的符號,分別賦予不一樣的數值編碼,以便於計算機的處理。 5.2字符集之間的轉換。 字符集多了,就會帶來一個問題,好比一個字符,在某一字符集中被編碼爲一個數值,而在另外一個字符集中被編碼爲另外一個數值,好比我來創造兩個字符集demo_charset1與demo_charset2,在demo_charset1中,我規定了三個符號的編碼爲:A(0001),B(0010),?(1111);而在demo_charset2中,我也規定了三個符號的編碼爲:A(1001),C(1011),?(1111),這時我接到一個任務,要編寫一個程序,負責在demo_charset1與demo_charset2之間進行轉換。因爲知道兩個字符集的編碼規則,對於demo_charset1中的0001,在轉換爲demo_charset2時,要將其編碼改成1001;對於demo_charset1中的1111,轉換爲demo_charset2時,其數值不變;而對於demo_charset1中的0010,其對應的字符爲B,但在demo_charset2沒有對應的字符,因此從理論上沒法轉換,對於全部這類沒法轉換的狀況,咱們能夠將它們統一轉換爲目標字符集中的一個特殊字符(稱爲「替換字符」),好比在這裏咱們能夠將?做爲替換字符,因此B就轉換爲了?,出現了信息的丟失;一樣道理,將demo_charset2的C字符轉換到demo_charset1時,也會出現信息丟失。 因此說,在字符集轉換過程當中,若是源字符集中的某個字符在目標字符集中沒有定義,將會出現信息丟失。 5.3數據庫字符集的選擇 咱們在建立數據庫時,須要考慮的一個問題就是選擇什麼字符集與國家字符集(經過create database中的CHARACTER SET與NATIONAL CHARACTER SET子句指定)。考慮這個問題,咱們必需要清楚數據庫中都須要存儲什麼數據,若是隻須要存儲英文信息,那麼選擇US7ASCII做爲字符集就能夠;可是若是要存儲中文,那麼咱們就須要選擇可以支持中文的字符集(如ZHS16GBK);若是須要存儲多國語言文字,那就要選擇UTF8了。 數據庫字符集的肯定,實際上說明這個數據庫所能處理的字符的集合及其編碼方式,因爲字符集選定後再進行更改會有諸多的限制,因此在數據庫建立時必定要考慮清楚後再選擇。而咱們許多朋友在建立數據庫時,不考慮清楚,每每選擇一個默認的字符集,如WE8ISO8859P1或US7ASCII,而這兩個字符集都沒有漢字編碼,因此用這種字符集存儲漢字信息從原則上說就是錯誤的。雖然在有些時候選用這種字符集好象也能正常使用,但它會給數據庫的使用與維護帶來一系列的麻煩,在後面的迭代過程當中咱們將深刻分析。 5.4客戶端的字符集 有過一些Oracle使用經驗的朋友,大多會知道經過NLS_LANG來設置客戶端的狀況,NLS_LANG由如下部分組成:NLS_LANG=_.,其中第三部分的本意就是用來指明客戶端操做系統缺省使用的字符集。因此按正規的用法,NLS_LANG應該按照客戶端機器的實際狀況進行配置,尤爲對於字符集一項更是如此,這樣Oracle就可以在最大程度上實現數據庫字符集與客戶端字符集的自動轉換(固然是若是須要轉換的話)。 5.5經過實例加深對基本概念的理解 下面我將引用網友tellin在ITPUB上發表的「CHARACTER SET研究及疑問」帖子,該朋友在帖子中列舉了他作的相關實驗,並對實驗結果提出了一些疑問,我將對他的實驗結果進行分析,並回答他的疑問。 5.5.1實驗結果分析一 最初由 tellin 發佈 設置客戶端字符集爲US7ASCII D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII 查看服務器字符集爲US7ASCII SQL> 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,導出後修改第2、三字符,修改 0001 爲0354,這樣就能夠將US7ASCII字符集的數據正確導入到ZHS16GBK的數據庫中」。我想對於這些結論,這樣理解可能更合適一些:因爲ZHS16GBK字符集是US7ASCII的超級,因此若是按正常操做,這種轉換應該沒有問題;但出現問題的本質是咱們讓本應只存儲英文字符的US7ASCII數據庫,很是規地存儲了中文信息,那麼在轉化過程當中出現錯誤或麻煩就沒什麼奇怪的了,不出麻煩卻是有些奇怪了。 因此說要避免這種狀況,就是要在創建數據庫時選擇合適的字符集,不讓標籤(數據庫的字符集設置)與實際(數據庫中實際存儲的信息)不符的狀況發生 5.5.2實驗結果分析二 [ 更改客戶端字符集爲ZHS16GBK D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK D:\>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」。 5.5.3實驗結果分析三 最初由 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個)。 更改客戶端字符集爲US7ASCII D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII D:\>SQLPLUS "/ AS SYSDBA" 沒法顯示用ZHS16GBK插入的字符集,但能夠顯示用US7ASCII插入的字符集 SQL> SELECT * FROM TEST; R1 ---------- 東北 ?? 更改服務器字符集爲ZHS16GBK SQL> update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET'; 1 row updated. SQL> COMMIT; 更改客戶端字符集爲ZHS16GBK D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK D:\>SQLPLUS "/ AS SYSDBA" 能夠顯示之前US7ASCII的字符集,但沒法顯示用ZHS16GBK插入的數據,說明用ZHS16GBK插入的數據爲亂碼。 SQL> SELECT * FROM TEST; R1 -------------------- 東北 ?? 須要指出的是,經過「update props$ set value$='ZHS16GBK' WHERE NAME='NLS_CHARACTERSET';」來修改數據庫字符集是很是規做法,極可能引發問題,在這裏只是原文引用網友的實驗結果。 5.5.4實驗結果分析四 SQL> INSERT INTO TEST VALUES('東北'); 1 row created. SQL> SELECT * FROM TEST; R1 -------------------- 東北 ?? 東北 SQL> EXIT 因爲此時數據庫與客戶端的字符集設置均爲ZHS16GBK,因此不會發生字符集的轉換,第一行與第三行數據顯示正確,而第二行因爲存儲的數據就是63(00111111),因此顯示的是「?」號。 更改客戶端字符集爲US7ASCII D:\>SET NLS_LANG=AMERICAN_AMERICA.US7ASCII D:\>SQLPLUS "/ AS SYSDBA" 沒法顯示數據 SQL> SELECT * FROM TEST; R1 ---------- ?? ?? ?? 疑問2:第一行數據是用US7ASCII環境插入的,爲什麼沒法正常顯示? 將客戶端字符集設置改成US7ASCII後進行SELECT,Oracle檢查發現數據庫設置的字符集爲ZHS16GBK,數據須要進行字符集轉換,而第一行與第三行的漢字「東」與「北」在客戶端字符集US7ASCII中沒有對應字符,因此轉換爲「替換字符」(「?」),而第二行數據在數據庫中存的原本就是兩個「?」號,因此雖然在客戶端顯示的三行都是兩個「?」號,但在數據庫中存儲的內容倒是不一樣的。 5.5.5實驗結果分析五 SQL> INSERT INTO TEST VALUES('東北'); 1 row created. SQL> EXIT 更改客戶端字符集爲ZHS16GBK D:\>SET NLS_LANG=AMERICAN_AMERICA.ZHS16GBK D:\>SQLPLUS "/ AS SYSDBA" 沒法顯示用US7ASCII插入的字符集,但能夠顯示用ZHS16GBK插入的字符集[/COLOR] SQL> SELECT * FROM TEST; R1 -------------------- 東北 ?? 東北 6+11 SQL> 疑問3:US7ASCII爲ZHS16GBK的子集,爲什麼在US7ASCII環境下插入的數據沒法顯示? 在客戶端字符集設置爲US7ASCII時,向字符集爲ZHS16GBK的數據庫中插入「東北」,須要進行字符轉換,「東北」的ZHS16GBK編碼爲182(10110110)、171(10101011)與177(10110001)、 177(10110001),因爲US7ASCII爲7bit編碼,Oracle將這兩個漢字看成四個字符,並忽略各字節的最高位,從而存入數據庫的編碼就變成了54(00110110)、43(00101011)與49(00110001)、49(00110001),也就是「6+11」,原始信息被改變了。這時,將客戶端字符集設置爲ZHS16GBK再進行SELECT,數據庫中的信息不須要改變傳到客戶端,第1、三行因爲存入的信息沒有改變能顯示「東北」,而第2、四行因爲插入數據時信息改變,因此不能顯示原有信息了。 6 兩條原則 分析了這麼多的內容,但實際上總結起來也很簡單,要想在字符集方面少些錯誤與麻煩,須要堅持兩條基本原則: 在數據庫端:選擇須要的字符集(經過Create Database中的CHARACTER SET與NATIONAL CHARACTER SET子句指定); 在客戶端:設置操做系統實際使用的字符集(經過環境變量NLS_LANG設置)。 7 參考 1 《理解ORACLE數據庫字符集》 轉載於網絡,來源不明,內容有刪減,謹致感謝。 2 《Oracle數據庫字符集問題解析》轉載於ITPUB論壇,謹致感謝sql

相關文章
相關標籤/搜索