当前位置: 代码迷 >> Oracle技术 >> 修改ORACLE11G,字符集的有关问题
  详细解决方案

修改ORACLE11G,字符集的有关问题

热度:141   发布时间:2016-04-24 08:31:40.0
修改ORACLE11G,字符集的问题
ORACLE instance shut down.
SQL> startup mount exclusive  
ORACLE instance started.

Total System Global Area 506368000 bytes
Fixed Size 1337520 bytes
Variable Size 318768976 bytes
Database Buffers 180355072 bytes
Redo Buffers 5906432 bytes
Database mounted.
SQL> alter system enable restricted session;

System altered.

SQL> alter database character set INTERNAL_USE ZHS16GBK;
alter database character set INTERNAL_USE ZHS16GBK
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01109: database not open


WHY????

------解决方案--------------------
SQL code
-- 3.5 字符集的更改 ( P94 )-- 数据库创建以后,如果需要修改字符集,通常需要重建数据库,通过导入导出的方式来转换。也可以通过以下方式更改:ALTER DATABASE CHARACTER SET-- 注意修改数据库字符集时必须谨慎,修改之前一定要为数据库备份。由于不能回退这项操作,因此可能会造成数据丢失或者损坏。-- 这是最简单的转换字符集的方式,但并不是总是有效。这个命令在Oracle 8时被引入Oracle,这个操作在本质上并不转换任何数据库字符,-- 只是简单地更新数据库中所有跟字符集相关的信息。-- 这意味着只能在新字符集是旧字符集严格超集的情况下使用这种方式转换。所谓超集是指当前字符集中的每一个字符集在新字符集中都可以表示,并使用相同的代码点,-- 比如很多字符集都是US7ASCII的严格超集。-- 如果不是超集将获得以下错误:SQL> ALTER DATABASE CHARACTER SET ZHS16CGB231280;*ERROR at line 1:ORA-12712: new character_set_must bu a superset of old character set-- 下面来看一个测试(以下测试在Oracle 9.2.0下进行,Oracle 9i较Oracle 8i在编码方面有较大改变,在Oracle 8i中,测试结果可能略有不同):SQL> select name, value$ from props$ where name like '%NLS%';NAME                      VALUE$------------------------- -----------------------------------NLS_LANGUAGE              AMERICANNLS_NCHAR_CHARACTERSET    AL16UTF16NLS_TERRITORY             AMERICANLS_CURRENCY              $NLS_ISO_CURRENCY          AMERICANLS_NUMERIC_CHARACTERS    .,NLS_CHARACTERSET          AL32UTF8NLS_CALENDAR              GREGORIANNLS_DATE_FORMAT           DD-MON-RRNLS_DATE_LANGUAGE         AMERICANNLS_SORT                  BINARYNLS_TIME_FORMAT           HH.MI.SSXFF AMNLS_TIMESTAMP_FORMAT      DD-MON-RR HH.MI.SSXFF AMNLS_TIME_TZ_FORMAT        HH.MI.SSXFF AM TZRNLS_TIMESTAMP_TZ_FORMAT   DD-MON-RR HH.MI.SSXFF AM TZRNLS_DUAL_CURRENCY         $NLS_COMP                  BINARYNLS_LENGTH_SEMANTICS      BYTENLS_NCHAR_CONV_EXCP       FALSENLS_RDBMS_VERSION         10.2.0.4.020 rows selected.create table scott.test(id number(18,0), name varchar2(20));insert into scott.test(id,name) values(1,'盖');insert into scott.test(id,name) values(2,'gai');SQL> select name, dump(name) from scott.test;......-- 转换字符集,数据库应该在RESTRICTED模式下进行:C:\> sqlplus "/ as sysdba"......SQL> shutdown immediate;......SQL> startup mount;SQL> ALTER SESSION SET SQL_TRACE=TRUE;......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> set linesize 140;SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;......SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;......-- 在Oracle 9i中,如果数据库存在CLOB类型字段,那么就不允许对字符集进行转换,这时可以去查看alert_<sid>.log日志文件,看CLOB字段存在于哪些表上:ALTER DATABASE CHARACTER SET ZHS16GBK SYS.METASTYLESHEET (STYLESHEET) - CLOB populatedORA-12716 signalled during: ALTER DATABASE CHARACTER SET ZHS16GBK...-- 对于不同的情况,Oracle 提供不同的解决方案,如果是用户数据表,一般我们可以把包含CLOB字段的表导出,然后drop掉相关对象,-- 转换后再导入数据库;对于系统表,可以按照以下方式处理:SQL> truncate table Metastylesheet;-- 然后可以继续进行转换:SQL> ALTER SESSION SET SQL_TRACE=TRUE;SQL> ALTER DATABASE CHARACTER SET ZHS16GBK;SQL> ALTER SESSION SET SQL_TRACE=FALSE;-- 在Oracle 9.2.0中,转换完成以后,可以通过运行catmet.sql脚本来重建Metastylesheet表:SQL> @?/rdbsm/admin/catmet.sql-- 转换后的数据:SQL> select name, value$ from prop$ where name like '%NLS%';-- 提示-- 通过设置 sql_trace,可以跟踪很多数据库的后台操作,这个工具是DBA常用的“利器”之一。strace -o sqlp.log sqlplus "/ as sysdba"-- 简单看一下数据库更改字符集时的后台处理,这里提取了主要的更新部分。-- 通过以下跟踪过程,可以看到数据库在更改字符集的时候 ,主要更新了12张数据字典表,修改了数据库的原数据,这也证实了我们以前的说法,-- 这个更改字符集的操作在本质上并不转换任何数据库字符,只是简单地更新数据库中所有跟字符集相关的信息。......-- 在这里纠正一个由来已久的错误方法,经常可以在网上看到这样的更改字符集的方法,这种方法应该被忘记,绝对不应该被采用:-- *(1) 用SYS用户登录ORACLE。-- *(2) 查看字符集内容        SELECT * FROM props$;-- *(3) 修改字符集  update props$ set value$='ZHS16GBK' where name='NLS_CHARACTERSET';  update props$ set value$='AL32UTF8' where name='NLS_CHARACTERSET';-- 很多人在这个问题上遇到了惨痛的教训。使用这种方式更改字符集,如果你的value$值输入了不正确的字符集,那么在Oracle 8i中你的数据库就可能会无法启动。-- 这种情况是非常严重的,有时候你必须从备份中进行恢复;如果是在Oracle 9i中,可以重新启动数据库后再修改回正确的字符集。实际上当更新了字符集,-- 数据库启动时会根据数据库的字符集自动地来修改控制文件的字符集,如果字符集可以识别,更新控制文件字符集等于数据库字符集;-- 如果字符集不可识别,那么控制文件字符集更新为US7ASCII。-- 以下是我的测试结果,但是严禁一切不备份的修改研究,即使是对测试库的。SQL> update props$ set value$='EYGLE' where name='NLS_CHARACTERSET';SQL> COMMIT;SQL> SELECT name, value$ from props$ where name like '%NLS%';-- 重新启动数据库,发现alter.log文件中记录如下操作:Mon Nov 03 16:11:35 2003Updating character set in controlfile to US7ASCIICompleted: ALTER DATABASE OPEN-- 启动数据库后恢复字符集设置:SQL> update props$ set value$='ZHS16GBK' where name='NLS_CHARACTERSET';......SQL> commit;......SQL> select name, value$ from props$ where name like '%NLS%';......-- 重新启动数据库后,发现控制文件的字符集被更新:Mon Nov 03 16:21:41 2003Updating character set in controlfile to ZHS16GBKCompleted: ALTER DATABASE OPEN-- 理解了字符集调用的内部操作以后,我们可以轻易地指出,以上方法是不正确的,通过前面“ALTER DATABASE CHARACTER SET”方式更改字符集时,-- Oracle 至少需要更改12张数据字典表,而这种直接更新props$表的方式只完成了其中十二分之一的工作,潜在的完整性隐患是可想而知的。-- 所以,更改字符集尽量要使用正常的途径。
  相关解决方案