理解ORACLE数据库字W集
耿立?br>Q中国科学院计算机网l信息中心,北京100080Q?/font>
一Q引a
ORACLE数据库字W集Q即Oracle全球化支?Globalization Support)Q或卛_家语a支持QNLSQ其作用是用本国语言和格式来存储、处理和索数据。利用全球化支持QORACLE为用h供自q(zhn)的数据 库母语环境,诸如日期格式、数字格式和存储序列{。Oracle可以支持多种语言及字W集Q其中oracle8i支持48U语a?6个国家地域?29 U字W集Q而oracle9i则支?7U语a?8个国家地域?35U字W集。由于oracle字符集种cdQ且在存储、检索、迁Uoracle数据 时多个环节与字符集的讄密切相关Q因此在实际的应用中Q数据库开发和理人员l常会遇到有关oracle字符集方面的问题。本文通过以下几个斚w阐述Q? 对oracle字符集做要分?/p>
二.字符集基本知?/strong>
2.1字符?br> 实质是按照一定的字符~码Ҏ(gu)Q对一l特定的W号Q分别赋予不同数值编码的集合。Oracle数据库最早支持的~码Ҏ(gu)是US7ASCII?br> Oracle的字W集命名遵@以下命名规则:
<Language><bit size><encoding>
? <语言><比特位数><~码>
比如: ZHS16GBK表示采用GBK~码格式?6位(两个字节Q简体中文字W集
2.2字符~码Ҏ(gu)
2.2.1 单字节编?br> Q?Q单字节7位字W集Q可以定?28个字W,最常用的字W集为US7ASCII
Q?Q单字节8位字W集Q可以定?56个字W,适合于欧z大部分国家
例如QWE8ISO8859P1(西欧?位、ISO标准8859P1~码)
2.2.2 多字节编?br> Q?Q变长多字节~码
某些字符用一个字节表C,其它字符用两个或多个字符表示Q变长多字节~码常用于对亚洲语言的支持, 例如日语、汉语、印地语{?br> 例如QAL32UTF8Q其中AL代表ALL,指适用于所有语aQ、zhs16cgb231280
Q?Q定长多字节~码
每一个字W都使用固定长度字节的编码方案,目前oracle唯一支持的定长多字节~码是AF16UTF16Q也是仅用于国家字符?br>2.2.3 unicode~码
Unicode是一个涵盖了目前全世界用的所有已知字W的单一~码Ҏ(gu)Q也是说Unicode为每一个字W提供唯一的编码。UTF-16?
unicode?6位编码方式,是一U定长多字节~码Q用2个字节表CZ个unicode字符QAF16UTF16是UTF-16~码字符集?br> UTF-8是unicode?位编码方式,是一U变长多字节~码Q这U编码可以用1??个字节表CZ个unicode字符QAL32UTF8QUTF8、UTFE是UTF-8~码字符?/p>
2.3 字符集超U?br> 当一U字W集Q字W集AQ的~码数值包含所有另一U字W集Q字W集BQ的~码数|q且两种字符集相同编码数g表相同的字符Ӟ则字W集A是字W集B的超U,或称字符集B是字W集A的子集?br> Oracle8i和oracle9i官方文档资料中备有子?对照表(subset-superset pairsQ,例如QWE8ISO8859P1是WE8MSWIN1252的子集。由于US7ASCII是最早的Oracle数据库编码格式,因此有许? 字符集是US7ASCII的超集,例如WE8ISO8859P1、ZHS16CGB231280、ZHS16GBK都是US7ASCII的超集?/p>
2.4 数据库字W集Qoracle服务器端字符集)
数据库字W集在创建数据库时指定,在创建后通常不能更改。在创徏数据库时Q可以指定字W集(CHARACTER SET)和国家字W集(NATIONAL CHARACTER SET)?br>2.4.1字符?br> (1)用来存储CHAR, VARCHAR2, CLOB, LONG{类型数?br> (2)用来标示诸如表名、列名以及PL/SQL变量{?br> (3)用来存储SQL和PL/SQLE序单元{?br>2.4.2国家字符集:
(1)用以存储NCHAR, NVARCHAR2, NCLOB{类型数?br>
(2)国家字符集实质上是ؓoracle选择的附加字W集Q主要作用是Z增强oracle的字W处理能力,因ؓNCHAR数据cd可以提供对亚z用定
长多字节~码的支持,而数据库字符集则不能。国家字W集在oracle9i中进行了重新定义Q只能在unicode~码中的AF16UTF16和UTF8
中选择Q默认值是AF16UTF16
2.4.3查询字符集参?br> 可以查询以下数据字典或视图查看字W集讄情况
nls_database_parameters、props$、v$nls_parameters
查询l果中NLS_CHARACTERSET表示字符集,NLS_NCHAR_CHARACTERSET表示国家字符?br>2.4.4修改数据库字W集
按照上文所_数据库字W集在创建后原则上不能更攏V如果需要修改字W集Q通常需要导出数据库数据Q重建数据库Q再导入数据库数据的方式来{换,或通过
ALTER DATABASE CHARACTER
SET语句修改字符集,但创建数据库后修改字W集是有限制的,只有新的字符集是当前字符集的集时才能修Ҏ(gu)据库字符集,例如UTF8是US7ASCII
的超集,修改数据库字W集可用ALTER DATABASE CHARACTER SET UTF8?/p>
2.5 客户端字W集QNLS_LANG参数Q?/strong> 三.导入/导出与字W集转换 3.1 EXP/IMP EXP IMP 四个字符集是 3.2导出的{换过E?br> 在Exportq程中,如果源数据库字符集与Export用户会话字符集不一_会发生字W集转换Qƈ在导出文件的头部几个字节中存储Export用户会话字符集的ID受在q个转换q程中可能发生数据的丢失?br>?
如果源数据库使用ZHS16GBKQ而Export用户会话字符集用US7ASCIIQ由于ZHS16GBK?6位字W集,而US7ASCII??
字符集,q个转换q程中,中文字符在US7ASCII中不能够扑ֈ对等的字W,所以所有中文字W都会丢p变?#8220;??
”形式Q这栯{换后生成的Dmp文g已经发生了数据丢失?br>因此如果x导出源数据库数据,则Exportq程中用户会话字W集应等于源数据库字W集或是源数据库字符集的集 3.3导入的{换过E?/strong> 四.q问题 oracle在数据存储、迁U过E中l常发生字符q问题Q归根到底是׃字符集用不当引赗下面以使用客户端sqlplus向数据库插入数据和导?导出QEXP/IMPQ过Eؓ例,说明q产生的原因?/p>
4.1使用客户端sqlplus向数据库存储数据 4.2发生q原因 4.3导入/导出q程出现q原因 五.单字节编码存储中文问?/strong> ׃历史的原因,早期的oracle没有中文字符集(如oracle6、oracle7?
oracle7.1Q?但有的用户从那时起就使用数据库了Qƈ用US7ASCII字符集存储了中文Q或是有的用户在创徏数据库时Q不考虑清楚Q随意选择一
个默认的字符集,如WE8ISO8859P1或US7ASCIIQ而这两个字符集都没有汉字~码Q虽然有些时候选用q种字符集好象也能正怋用,但用q种
字符集存储汉字信息从原则上说是错误的,它会l数据库的用与l护带来一pd的麻烦?br>
正常情况下,要将汉字存入数据库,数据库字W集必须支持中文Q而将数据库字W集讄为US7ASCII{单字节字符集是不合适的。US7ASCII字符?
只定义了128个符Pq不支持汉字。另外,如果在SQL*PLUS中能够输入中文,操作pȝ~省应该是支持中文的Q但如果在NLS_LANG中的字符?
讄为US7ASCIIQ显然也是不正确的,它没有反映客L(fng)的实际情c但在实际应用中汉字昄却是正确的,q主要是因ؓOracle查数据库与客?
端的字符集设|是同样的,那么数据在客户与数据库之间的存取q程中将不发生Q何{换,但是q实际上D了数据库标识的字W集与实际存入的内容是不相符的?
而在SELECT的过E中QOracle同样查发现数据库与客L(fng)的字W集讄是相同的Q所以它也将存入的内容原不动地传送到客户端,而客L(fng)操作p?
l识别出q是汉字~码所以能够正显C?br> 在这个例子中Q数据库与客L(fng)都没有设|成中文字符集,但却能正常显CZ文,从应用的角度看好象没问题。然而这里面却存在着极大的隐(zhn),比如在应用length或substr{字W串函数Ӟ可能得到意外的l果?br>
对于早期使用US7ASCII字符集数据库的数据迁Udoracle8i/9i中(使用zhs16gbkQ,׃原始数据已经按照US7ASCII格式?
储,对于q种情况Q可以通过使用Oracle8i的导出工P讄导出字符集ؓUS7ASCIIQ导出后使用UltraEdit{工h开dmp文gQ修
改第二、三字符Q修?0001 ?354,q样可以将US7ASCII字符集的数据正确导入到ZHS16GBK的数据库中?/p>
六.l束?/strong> Z避免在数据库q移q程中由于字W集不同D的数据损失,oracle提供了字W集扫描工具Qcharacter set
scannerQ,通过q个工具我们可以试在数据迁U过E中׃字符集{换可能带来的问题Q然后根据测试结果,定数据q移q程中最?jng)_W集解决Ҏ(gu)?/p>
2.5.1客户端字W集含义
客户端字W集定义了客L(fng)字符数据的编码方式,M发自或发往客户端的字符数据均用客L(fng)定义的字W集~码,客户端可以看作是能与数据库直接连接的各种应用Q例如sqlplus,exp/imp{。客L(fng)字符集是通过讄NLS_LANG参数来设定的?br>2.5.2 NLS_LANG参数格式
NLS_LANG=<language>_<territory>.<client character set>
Language:昄oracle消息,校验Q日期命?br> TerritoryQ指定默认日期、数字、货币等格式
Client character setQ指定客L(fng)用的字符?br> 例如QNLS_LANG=AMERICAN_AMERICA.US7ASCII
AMERICAN是语aQAMERICA是地区,US7ASCII是客L(fng)字符?br>2.5.3客户端字W集讄Ҏ(gu)
1)UNIX环境
$NLS_LANG=“simplified chinese”_china.zhs16gbk
$export NLS_LANG
~辑oracle用户的profile文g
2)Windows环境
~辑注册?br> Regedit.exe---HKEY_LOCAL_MACHINE---SOFTWARE---ORACLE—HOME0
2.5.4 NLS参数查询
Oracle提供若干NLS参数定制数据库和用户Z适应本地格式Q例如有NLS_LANGUAGE,NLS_DATE_FORMAT,NLS_CALENDER{,可以通过查询以下数据字典或v$视图查看?br> NLS_DATABASE_PARAMETERS--昄数据库当前NLS参数取|包括数据库字W集取?br> NLS_SESSION_PARAMETERS--昄由NLS_LANG 讄的参敎ͼ或经qalter session 改变后的参数|不包括由NLS_LANG 讄的客L(fng)字符集)
NLS_INSTANCE_PARAMETE--昄由参数文件init<SID>.ora 定义的参数V$NLS_PARAMETERS--昄数据库当前NLS参数取?br>2.5.5修改NLS参数
使用下列Ҏ(gu)可以修改NLS参数
Q?Q修改实例启动时使用的初始化参数文g
Q?Q修改环境变量NLS_LANG
Q?Q用ALTER SESSION语句Q在oracle会话中修?br> Q?Q用某些SQL函数
NLS作用优先U别QSql function>alter session>环境变量或注册表>参数文g>数据库默认参?/p>
Export ?Import
是一对读写Oracle数据的工兗Export ?Oracle 数据库中的数据输出到操作pȝ文g? Import
把这些文件中的数据读到Oracle
数据库中Q由于用exp/impq行数据q移Ӟ数据从源数据库到目标数据库的q程中有四个环节涉及到字W集Q如果这四个环节的字W集不一_会发生
字符集{换?/p>
Q?Q源数据库字W集
Q?QExportq程中用户会话字W集Q通过NLS_LANG讑֮Q?br> Q?QImportq程中用户会话字W集Q通过NLS_LANG讑֮Q?br> Q?Q目标数据库字符?/p>
Q?Q确定导出数据库字符集环?br> 通过d导出文g_可以获得导出文g的字W集讄
Q?Q确定导入session的字W集Q即导入Session使用的NLS_LANG环境变量
Q?QIMPd导出文g
d导出文g字符集IDQ和导入q程的NLS_LANGq行比较
Q?Q如果导出文件字W集和导入Session字符集相同,那么在这一步骤内就不需要{换,如果不同Q就需要把数据转换为导入Session使用的字W集。可以看出,导入数据到数据库q程中发生两ơ字W集转换
W一?导入文g字符集与导入Session使用的字W集之间的{换,如果q个转换q程不能正确完成QImport向目标数据库的导入过E也׃能完成?br> W二?导入Session字符集与数据库字W集之间的{换?br>
然?oracle8i的这U{换只能在单字节字W集之间q行,oracle8i导入Session不支持多字节字符集之间的转换Q因此ؓ了避免第一ơ{
换,导入Session使用的NLS_LANG与导出文件字W集相同Q第二次转换Q通过SQL*NetQ支持Q何两U字W集。以上情况在Oracle9i
中略有不?/p>
q个q程存在3个字W集讄
Q?Q客L(fng)应用字符?br> Q?Q客L(fng)NLS_LANG参数讄
Q?Q服务器端数据库字符?Character Set)讄
客户端应用sqlplus中能够显CZ么样的字W取决于客户端操作系l语a环境(客户端应用字W集)Q但在应用中录入q些字符后,q些字符能否在数据库?
正常存储Q还与另外两个字W集讄紧密相关Q其中客L(fng)NLS_LANG参数主要用于字符数据传输q程中的转换判断。常见的q大致有两U情形:
Q?Q汉字变成问?#8220;Q?#8221;Q?br>当从字符集A 转换成字W集BӞ如果转换字符之间不存在对应关p,NLS_LANG使用替代字符“Q?#8221;替代无法映射的字W?br> Q?Q汉字变成未知字W(虽然有些是汉字,但与原字W含义不同)
转换存在对应关系Q但字符集A 中的字符~码与字W集B 中的字符~码代表不同含义
q产生是由于几个字W集之间转换不匹配造成Q分以下几种情况Q?br> Q注Q字W集之间如果不存在子集、超集对应关pL的情况不予考虑Q因U情况下字符集之间{换必产生qQ?nbsp;
1Q服务器端数据库字符集与客户端应用字W集相同Q与客户端NLS_LANG参数讄不同
如果客户端NLS_LANG字符集是其它两种字符集的子集Q{换过E将出现q?br> 解决Ҏ(gu)Q将三种字符集设|成同一字符集,或NLS_LANG字符集是其它两种字符集的集
2Q服务器端数据库字符集与客户端NLS_LANG参数讄相同Q与客户端应用字W集不同
如果客户端应用字W集是其它两U字W集的超集时Q{换过E将出现qQ但对于单字节编码存储中文问题,可参看本文第5章节的分?br> 3Q客L(fng)应用字符集、客L(fng)NLS_LANG参数讄、服务器端数据库字符集互不相?br> 此种情况较ؓ复杂Q但三种字符集之间只要有不能转换的字W,则必产生q
q个q程存在4个字W集讄Q在3.1章节中已分析
Q?Q源数据库字W集
Q?QEXPq程中NLS_LANG参数
Q?QIMPq程中NLS_LANG参数
Q?Q目标数据库字符?br> 出现q原因
1Q当源数据库字符集不{于EXPq程中NLS_LANG参数Q且源数据库字符集是EXPq程中NLS_LANG的子集,才能保证导出文g正确Q其他情况则导出文g字符q
2QEXPq程中NLS_LANG字符集不{于IMPq程中NLS_LANG字符集,且EXPq程中NLS_LANG字符集是IMPq程中NLS_LANG字符集的子, 才能保证W一ơ{换正常,否则W一ơ{换中出现q?br> 3Q如果第一ơ{换正常,IMPq程中NLS_LANG字符集是目标数据库字W集的子集或相同Q才能保证第二次转换正常Q否则则W二ơ{换中出现q
参考文?/strong>
[1]Biju Thomas , Bob Bryla《oracle9i DBA基础I 学习指南》电(sh)子工业出版社 2002
[2]|站 http://www.itpub.net
]]>