有一个建好的数据,Oracle 9.2.0.4 for linux,字符集是缺省的WE8ISO8859P1,没有改成ZHS16GBK. 库中暂时没有任何数据。 由于字符集不是超集/子集关系,无法通过ALTER DATABASE CHARACTER SET修改字符集。 当时时间紧张,就没有重建数据库,而是直接修改prop$表,将NLS_CHAR字符集改为ZHS16GBK. 0update props$ set value$= ZHS16GBK where name= NLS_CHARACTERSET ;重启后建表、insert数据,一切正常……直到今天要exp出数据。 执行 exp userid=system owner=username …… 报错! 即将导出指定的用户… 正在导出 pre-schema 过程对象和操作 正在导出用户 USERNAME 的外部函数库名称 导出 PUBLIC 类型同义词 EXP-00008: 遇到 ORACLE 错误 6552 ORA-06552: PL/SQL: Compilation unit analysis terminated ORA-06553: PLS-553: character set name is not recognized EXP-00000: 导出终止失败 隐隐感觉与当时的字符集设置有关 “正式修改字符集时,Oracle至少需要更改12张数据字典表,而这种直接更新props$表的方式只完成了其中十二分之一的工作,潜在的完整性隐患是可想而知的。” 但是如何解决呢?后来搜索到未公开的INTERNAL_USE用法,强制完成字符集一致化,解决了问题。 首先,确认字符集是否修改的不彻底。 SELECT DISTINCT (NLS_CHARSET_NAME(CHARSETID)) CHARACTERSET, DECODE(TYPE#, 1, DECODE(CHARSETFORM, 1, VARCHAR2 , 2, NVARCHAR2 , UNKOWN ), 9, DECODE(CHARSETFORM, 1, VARCHAR , 2, NCHAR VARYING , UNKOWN ), 96, DECODE(CHARSETFORM, 1, CHAR , 2, NCHAR , UNKOWN ), 112, DECODE(CHARSETFORM, 1, CLOB , 2, NCLOB , UNKOWN )) TYPES_USED_IN FROM SYS.COL$ WHERE CHARSETFORM IN (1, 2) AND TYPE# IN (1, 9, 96, 112). 如果上面的查询的确显示有多个字符集的设定,则进行如下处理:SHUTDOWN IMMEDIATE; STARTUP MOUNT. ALTER SYSTEM ENABLE RESTRICTED SESSION. ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0. ALTER SYSTEM SET AQ_TM_PROCESSES=0. ALTER DATABASE OPEN. COL VALUE NEW_VALUE CHARSET SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER= NLS_CHARACTERSET . COL VALUE NEW_VALUE NCHARSET SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER= NLS_NCHAR_CHARACTERSET . ——INTERNAL_USE是没有写在文档中的参数,用以强制完成字符集一致化 ALTER DATABASE CHARACTER SET INTERNAL_USE &.CHARSET. ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_USE &.NCHARSET. SHUTDOWN IMMEDIATE. STARTUP. —— 再次启动数据库一遍 SHUTDOWN IMMEDIATE. STARTUP. 至此,EXP问题得到了解决。 注意:修改字符集只是修改了数据字典,并没有对数据进行字符集转换!