oracle字符集

来源:百度文库 编辑:神马文学网 时间:2024/03/29 17:25:37
一.引言

ORACLE数据库字符集,即Oracle全球化支持(Globalization Support),或即国家语言支持(NLS)其作用是用本国语言和格式来存储、处理和检索数据。利用全球化支持,ORACLE为用户提供自己熟悉的数据库母语环境,诸如日期格式、数字格式和存储序列等。Oracle可以支持多种语言及字符集,其中oracle8i支持48种语言、76个国家地域、229种字符集,而oracle9i则支持57种语言、88个国家地域、235种字符集。由于oracle字符集种类多,且在存储、检索、迁移oracle数据时多个环节与字符集的设置密切相关,因此在实际的应用中,数据库开发和管理人员经常会遇到有关oracle字符集方面的问题。本文通过以下几个方面阐述,对oracle字符集做简要分析

二.字符集基本知识

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位编码方式,是一种变长多字节编码,这种编码可以用1、2、3个字节表示一个unicode字符,AL32UTF8,UTF8、UTFE是UTF-8编码字符集

2.3 字符集超级
当一种字符集(字符集A)的编码数值包含所有另一种字符集(字符集B)的编码数值,并且两种字符集相同编码数值代表相同的字符时,则字符集A是字符集B的超级,或称字符集B是字符集A的子集。
Oracle8i和oracle9i官方文档资料中备有子集-超级对照表(subset-superset pairs),例如:WE8ISO8859P1是WE8MSWIN1252的子集。由于US7ASCII是最早的Oracle数据库编码格式,因此有许多字符集是US7ASCII的超集,例如WE8ISO8859P1、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—HOME0
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.1 EXP/IMP
Export 和 Import 是一对读写Oracle数据的工具。Export 将 Oracle 数据库中的数据输出到操作系统文件中, Import 把这些文件中的数据读到Oracle 数据库中,由于使用exp/imp进行数据迁移时,数据从源数据库到目标数据库的过程中有四个环节涉及到字符集,如果这四个环节的字符集不一致,将会发生字符集转换。

EXP
____________ _________________ _____________
|imp导入文件|<-|环境变量NLS_LANG|<-|数据库字符集|
------------ ----------------- -------------


IMP
____________ _________________ _____________
|imp导入文件|->|环境变量NLS_LANG|->|数据库字符集|
------------ ----------------- -------------


四个字符集是
(1)源数据库字符集
(2)Export过程中用户会话字符集(通过NLS_LANG设定)
(3)Import过程中用户会话字符集(通过NLS_LANG设定)
(4)目标数据库字符集

3.2导出的转换过程
在Export过程中,如果源数据库字符集与Export用户会话字符集不一致,会发生字符集转换,并在导出文件的头部几个字节中存储Export用户会话字符集的ID号。在这个转换过程中可能发生数据的丢失。
例:如果源数据库使用ZHS16GBK,而Export用户会话字符集使用US7ASCII,由于ZHS16GBK是16位字符集,而US7ASCII是7位字符集,这个转换过程中,中文字符在US7ASCII中不能够找到对等的字符,所以所有中文字符都会丢失而变成“?? ”形式,这样转换后生成的Dmp文件已经发生了数据丢失。
因此如果想正确导出源数据库数据,则Export过程中用户会话字符集应等于源数据库字符集或是源数据库字符集的超集

3.3导入的转换过程
(1)确定导出数据库字符集环境
通过读取导出文件头,可以获得导出文件的字符集设置
(2)确定导入session的字符集,即导入Session使用的NLS_LANG环境变量
(3)IMP读取导出文件
读取导出文件字符集ID,和导入进程的NLS_LANG进行比较
(4)如果导出文件字符集和导入Session字符集相同,那么在这一步骤内就不需要转换,如果不同,就需要把数据转换为导入Session使用的字符集。可以看出,导入数据到数据库过程中发生两次字符集转换
第一次:导入文件字符集与导入Session使用的字符集之间的转换,如果这个转换过程不能正确完成,Import向目标数据库的导入过程也就不能完成。
第二次:导入Session字符集与数据库字符集之间的转换。
然而,oracle8i的这种转换只能在单字节字符集之间进行,oracle8i导入Session不支持多字节字符集之间的转换,因此为了避免第一次转换,导入Session使用的NLS_LANG与导出文件字符集相同,第二次转换(通过SQL*Net)支持任何两种字符集。以上情况在Oracle9i中略有不同

四.乱码问题

oracle在数据存储、迁移过程中经常发生字符乱码问题,归根到底是由于字符集使用不当引起。下面以使用客户端sqlplus向数据库插入数据和导入/导出(EXP/IMP)过程为例,说明乱码产生的原因。

4.1使用客户端sqlplus向数据库存储数据
这个过程存在3个字符集设置
(1)客户端应用字符集
(2)客户端NLS_LANG参数设置
(3)服务器端数据库字符集(Character Set)设置
客户端应用sqlplus中能够显示什么样的字符取决于客户端操作系统语言环境(客户端应用字符集),但在应用中录入这些字符后,这些字符能否在数据库中正常存储,还与另外两个字符集设置紧密相关,其中客户端NLS_LANG参数主要用于字符数据传输过程中的转换判断。常见的乱码大致有两种情形:
(1)汉字变成问号“?”;
当从字符集A 转换成字符集B时,如果转换字符之间不存在对应关系,NLS_LANG使用替代字符“?”替代无法映射的字符
(2)汉字变成未知字符(虽然有些是汉字,但与原字符含义不同)
转换存在对应关系,但字符集A 中的字符编码与字符集B 中的字符编码代表不同含义

4.2发生乱码原因
乱码产生是由于几个字符集之间转换不匹配造成,分以下几种情况:
(注:字符集之间如果不存在子集、超集对应关系时的情况不予考虑,因为这种情况下字符集之间转换必产生乱码)
1)服务器端数据库字符集与客户端应用字符集相同,与客户端NLS_LANG参数设置不同
如果客户端NLS_LANG字符集是其它两种字符集的子集,转换过程将出现乱码。
解决方法:将三种字符集设置成同一字符集,或NLS_LANG字符集是其它两种字符集的超集
2)服务器端数据库字符集与客户端NLS_LANG参数设置相同,与客户端应用字符集不同
如果客户端应用字符集是其它两种字符集的超集时,转换过程将出现乱码,但对于单字节编码存储中文问题,可参看本文第5章节的分析
3)客户端应用字符集、客户端NLS_LANG参数设置、服务器端数据库字符集互不相同
此种情况较为复杂,但三种字符集之间只要有不能转换的字符,则必产生乱码

4.3导入/导出过程出现乱码原因
这个过程存在4个字符集设置,在3.1章节中已分析
(1)源数据库字符集
(2)EXP过程中NLS_LANG参数
(3)IMP过程中NLS_LANG参数
(4)目标数据库字符集
出现乱码原因
1)当源数据库字符集不等于EXP过程中NLS_LANG参数,且源数据库字符集是EXP过程中NLS_LANG的子集,才能保证导出文件正确,其他情况则导出文件字符乱码
2)EXP过程中NLS_LANG字符集不等于IMP过程中NLS_LANG字符集,且EXP过程中NLS_LANG字符集是IMP过程中NLS_LANG字符集的子级, 才能保证第一次转换正常,否则第一次转换中出现乱码。
3)如果第一次转换正常,IMP过程中NLS_LANG字符集是目标数据库字符集的子集或相同,才能保证第二次转换正常,否则则第二次转换中出现乱码

五.单字节编码存储中文问题

由于历史的原因,早期的oracle没有中文字符集(如oracle6、oracle7、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文件,修改第二、三字符,修改 0001 为0354,这样就可以将US7ASCII字符集的数据正确导入到ZHS16GBK的数据库中。

六.结束语

为了避免在数据库迁移过程中由于字符集不同导致的数据损失,oracle提供了字符集扫描工具(character set scanner),通过这个工具我们可以测试在数据迁移过程中由于字符集转换可能带来的问题,然后根据测试结果,确定数据迁移过程中最佳字符集解决方案。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------lsb_release -a locale -a
测试的时候,本机oracle安装采用了utf8字符集,而项目的要求是gbk字符集,为了防止 以后有不同字符集数据信息导入导出的疑问,整理以下文档。  修改oracle字符集新装了oracle,装为AL32UTF8格式,无奈一个工程导出包是ZHS16GBK格式,想了想要领 转换,以下是学习  一、什么是oracle字符集  Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容联系。ORACLE 支撑国家语言的体系结构允许你运用本地化语言来存储,处理,检索数据。它使数据库工具,不正确消息,排序次序,日期,时间,货币,数字,和日历自动适应本地化语言和平台。  影响oracle数据库字符集最主要的参数是NLS_LANG参数。它的格式如下:  NLS_LANG = language_territory.charset  它有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特征。其中:  Language 指定服务器消息的语言,territory 指定服务器的日期和数字格式,charset 指定字符集。如:AMERICAN _ AMERICA. ZHS16GBK  从NLS_LANG的组成咱们可以看出,真实影响数据库字符集的其实是第三部分。所以两个数据库之间的字符集只要第三部分一样就可以相互导入导出数据,前面影响的只是提示信息是中文还是英文。  二、如何 查询Oracle的字符集  很多人都碰到过因为字符集不同而使数据导入失败的情况。这涉及三方面的字符集,一是oracel server端的字符集,二是oracle client端的字符集;三是dmp文件的字符集。在做数据导入的时候,须要这三个字符集都一致才能正确导入。  1、查询oracle server端的字符集  有很多种要领可以查出oracle server端的字符集,比较直观的查询要领是以下这种:SQL>select userenv('language') from dual;  结果类似如下:AMERICAN _ AMERICA. ZHS16GBK (本机结果SIMPLIFIED CHINESE_CHINA.AL32UTF8)  2、如何 查询dmp文件的字符集  用oracle的exp 工具导出的dmp文件也包含了字符集信息,dmp文件的第2和第3个字节记录了dmp文件的字符集。假如 dmp文件不大,比如只有几M或几十M,可以用UltraEdit打开(16进制形式 ),看第2第3个字节的内容,如0354,然后用以下SQL查出它对应的字符集:  SQL> select nls_charset_name(to_number('0354','xxxx')) from dual;  ZHS16GBK  假如 dmp文件很大,比如有2G以上(这也是最多见的情况),用文本编辑器打开很慢或者完全打不开,可以用以下命令(在unix主机上):  cat exp .dmp od -xhead -1awk '{print $2 $3}'cut -c 3-6  然后用上述SQL也可以得到它对应的字符集。  3、查询oracle client端的字符集  这个比较基本。在windows平台下,就是注册表里面HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOME0\NLS_LANG 。还可以在dos窗口里面自己配置,比如:  set nls_lang=AMERICAN_AMERICA.ZHS16GBK  这样就只影响这个窗口里面的环境变量。  在unix平台下,就是环境变量NLS_LANG。  $echo $NLS_LANG  AMERICAN_AMERICA.ZHS16GBK  假如检查的结果发觉 server端与client端字符集不一致,请统一修改为同server端相同的字符集。  三、修改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;  以上要领测试不可以,用scott/tiger登陆sqlplus然后connect sys/sys 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 INTERNAL_USE ZHS16GBK; //跳过超子集检测  SQL>ALTER DATABASE national CHARACTER SET INTERNAL ZHS16GBK;  这一行不起作用,执行后出错ORA-00933: SQL 命令未正确结束,不过执行上一行命令已经生效,其他文章里未提到本行。  SQL>SHUTDOWN IMMEDIATE;  SQL>STARTUP  2、修改dmp文件字符集  上文说过,dmp文件的第2第3字节记录了字符集信息,因此直接修改dmp文件的第2第3字节的内容就可以‘骗’过oracle的检查。这样做理论上也仅是从子集到超集可以修改,但很多情况下在没有子集和超集联系的情况下也可以修改,咱们常用的一些字符集,如US7ASCII,WE8ISO8859P1,ZHS16CGB231280,ZHS16GBK基本都可以改。因为改的只是dmp文件,所以影响不大。  细致 的修改要领比较多,最基本的就是直接用UltraEdit修改dmp文件的第2和第3个字节。比如想将dmp文件的字符集改为ZHS16GBK,可以用以下SQL查出该种字符集对应的16进制代码:  SQL> select to_char(nls_charset_id('ZHS16GBK'), 'xxxx') from dual;  0354  然后将dmp文件的2、3字节修改为0354即可。  假如 dmp文件很大,用ue无法 打开,就须要用程序的要领了。网上有人用java存储流程写了转换的程序(用java存储流程的优点是通用性教好,缺点是比较麻烦)。我在windows下测试通过。但要求oracle数据库一定要安装JVM选项。有兴趣的朋友可以研究一下程序代码
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没有备份的操作中得到了惨痛的教训 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 失效  
exp/imp时dmp文件字符集的转换 在导出操作时,非常重要的是客户端的字符集设置,也就是客户端的NLS_LANG设置。
NLS_LANG参数由以下部分组成:
NLS_LANG=_.
NLS_LANG各部分含义如下:
LANGUAGE指定:
-Oracle消息使用的语言
-日期中月份和日显示
TERRITORY指定
-货币和数字格式
-地区和计算星期及日期的习惯
CHARACTERSET:
-控制客户端应用程序使用的字符集
通常设置或者等于客户端(如Windows)代码页
或者对于unicode应用设置为UTF8
在Windows上查看当前系统的代码页可以使用chcp命令:
E:\>chcp
活动的代码页: 936
代码页936也就是中文字符集 GBK。通常在导出时最好把客户端字符集设置得和数据库端相同,这样可以避免在导出时发生不必要的数据转换,导出文件将和数据库具有相同的字符集。
即使将来会把导出文件导入到不同字符集的数据库中,这样做也可以把转换延缓至导入时刻。
当进行数据导入时,主要存在以下两种情况:
1.源数据库和目标数据库具有相同字符集设置
这时,只需要设置NLS_LANG等于数据库字符集即可导入(前提是,导出使用的是和源数据库相同字符集,即三者相同)
2.源数据库和目标数据库字符集不同
如果我们导出时候使用的NLS_LANG是和源数据库相同的字符集,那么导入时就可以设置客户端NLS_LANG等于导出时使用的字符集,这
样转换只发生在数据库端,而且只发生一次。dmp文件用UltraEdit打开查看十六进制文件,第2-3个字节表示字符集,假如是"03 54"。
0000000 0303 5445 5850 4f52 543a 3156 2e30 3230
0000020 302e 0a31 5344 5359 4554 0a4d 5552 4553
0000040 5352 380a 3931 0a32 0a30 3032 300a 000a
0000060 0301 0754 00d0 0001 0000 0000 0000 0000
0000100 0006 2020 2020 2020 2020 2020 2020 2020
0000120 2020 2020 2020 2020 2020 2020 2020 2020
0000140 2020 2020 2020 2020 5720 6465 4e20 766f
在Unix上我们可以通过以下命令来查看:cat expdat.dmp | od -x | head
查看这个十六进制id的十进制:
SQL> select to_number(354,'xxxx') from dual;
TO_NUMBER(1,'XXXX')
-------------------
                  1
查看这个十进制id表示的字符集:
SQL> select nls_charset_name(1) from dual;
NLS_CHARSET_NAME(1)
----------------------------------------
US7ASCII
查看目标字符集的十进制id:
SQL> select nls_charset_id('zhs16gbk') from dual;
NLS_CHARSET_ID('ZHS16GBK')
--------------------------
                       852
查看这个十进制id的十六进制:
SQL> select to_char(852,'xxxx') from dual;
TO_CHAR(852,'XXXX')
--------------------------------------------------------------------------------
354
dmp文件用UE打开,把"00 01"改为"03 54"即完成了字符集的转换。查询数据库中有效的字符集可以使用以下脚本:
col nls_charset_id for 9999
col nls_charset_name for a30
col hex_id for a20
select nls_charset_id(value) nls_charset_id, value nls_charset_name, to_char(nls_charset_id(value),'xxxx') hex_id
from v$nls_valid_values
where parameter = 'CHARACTERSET'
order by nls_charset_id(value);查询oracle server字符集:
select * from v$nls_database_parameters;
查询客户端登陆session字符集:
select * from v$nls_session_parameters;通常在我们的现实环境中,存在3个字符集设置。
第一: 客户端应用字符集(Client Application Character Set)
第二: 客户端NLS_LANG参数设置
第三: 服务器端,数据库字符集(Character Set)设置
我们说,一个字符在客户端应用(比如SQLPLUS,CMD,NOTEPAD等)中以怎样的字符显示取决于客户端操作系统,客户端能够显示怎样的字符,
我们就可以在应用中录入这些字符,至于这些字符能否在数据库中正常存储,就和另外的两个字符集设置紧密相关了。
在传输过程中,客户端NLS_LANG主要用于进行转换判断
如果NLS_LANG等于数据库字符集,则不进行任何转换直接把字符插入数据库
如果不同则进行转换,转换主要有两个任务
如果存在对应关系,则把相应二进制编码经过映射后(这一步映射以后,所代表的字符可能发生转换)传递给数据库
如果不存在对应关系,则传递一个替换字符(很多平台就是?)
数据库字符集,在和客户端NLS_LANG不同时,会把经过NLS_LANG转换的字符进行进一步处理
对于?(即不存在对应关系的字符)直接以?形式存放入数据库
对于其他字符,在NLS_LANG和数据库字符集之间进行转换后存入