字符集的更改

来源:互联网 发布:怎么投诉淘宝买家 编辑:程序博客网 时间:2024/05/02 03:31
字符集的更改 
-- 数据库创建以后,如果需要修改字符集,通常需要重建数据库,通过导入导出的方式来转换。也可以通过以下方式更改:
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              AMERICAN
NLS_NCHAR_CHARACTERSET    AL16UTF16
NLS_TERRITORY             AMERICA
NLS_CURRENCY              $
NLS_ISO_CURRENCY          AMERICA
NLS_NUMERIC_CHARACTERS    .,
NLS_CHARACTERSET          AL32UTF8
NLS_CALENDAR              GREGORIAN
NLS_DATE_FORMAT           DD-MON-RR
NLS_DATE_LANGUAGE         AMERICAN
NLS_SORT                  BINARY
NLS_TIME_FORMAT           HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT      DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT        HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT   DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY         $
NLS_COMP                  BINARY
NLS_LENGTH_SEMANTICS      BYTE
NLS_NCHAR_CONV_EXCP       FALSE
NLS_RDBMS_VERSION         10.2.0.4.0
20 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 populated
ORA-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 2003
Updating character set in controlfile to US7ASCII
Completed: 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 2003
Updating character set in controlfile to ZHS16GBK
Completed: ALTER DATABASE OPEN
-- 理解了字符集调用的内部操作以后,我们可以轻易地指出,以上方法是不正确的,通过前面“ALTER DATABASE CHARACTER SET”方式更改字符集时,
-- Oracle 至少需要更改12张数据字典表,而这种直接更新props$表的方式只完成了其中十二分之一的工作,潜在的完整性隐患是可想而知的。
-- 所以,更改字符集尽量要使用正常的途径。
识别导出文件的字符集 ( P98 )
-- 在传统的EXP导出文件中,记录着导出使用的字符集id,通过查看导出文件头的第2、3个字节,可以找到十六进制表示的字符集ID,
-- 在Windows上,可以使用 UltraEdit等工具打开dmp文件,查看其导出字符集,如图3-6所示。
......
exp system/bee56915 file=/u02/exp/scott011.dmp owner=scott
-- 在UNIX环境上,可以通过以下命令来查看(以下范例来自Solaris平台),如图3-7所示。


[oracle@sztyora exp]$ cat scott011.dmp | od -x | head -2
0000000 0003 4501 5058 524f 3a54 3156 2e30 3230
0000020 302e 0a31 5344 5359 4554 0a4d 5552 4553
0000040 5352 380a 3931 0a32 0a30 3032 300a 000a
0000060 0301 0769 00d0 0001 0000 0000 0000 0000
0000100 0015 2020 2020 2020 2020 2020 2020 2020
0000120 2020 2020 2020 2020 2020 2020 2020 2020
0000140 2020 2020 2020 2020 6153 2074 754a 206e
0000160 3632 3120 3a32 3933 353a 2037 3032 3031
0000200 752f 3230 652f 7078 732f 6f63 7474 3130
0000220 2e31 6d64 0070 0000 0000 0000 0000 0000


-- 需要注意的是,在不同平台,以上命令的输出可能有所不同,比如在Linux平台:
[oracle@sztyora exp]$  cat scott011.dmp | od -x | head -2
0000000 0003 4501 5058 524f 3a54 3156 2e30 3230
0000020 302e 0a31 5344 5359 4554 0a4d 5552 4553
-- 这是由于 Solaris 和 Linux 的字节序是不同的,Solaris 是 Big-Endians,Linux 是 Little-Endians,所以Linux上的输出通过交换可以得到:
-- 字符集和 Solaris 上是一致的,所以也可以通过od的参数设置显示格式:
[oracle@sztyora exp]$ cat scott011.dmp | od -t x1 | head -2
0000000 03 00 01 45 58 50 4f 52 54 3a 56 31 30 2e 30 32
0000020 2e 30 31 0a 44 53 59 53 54 45 4d 0a 52 55 53 45
-- Oracle 提供标准函数,对字符集名称及ID进行转换:
SQL> select nls_charset_id('ZHS16GBK') from dual;


NLS_CHARSET_ID('ZHS16GBK')
--------------------------
                       852
SQL> select nls_charset_name(852) from dual;
-- select nls_charset_id('AL32UTF8') from dual;
-- select nls_charset_name(873) from dual;
SQL> select to_char('873','xxxx') from dual;


TO_CH
-----
  369
-- 对应图3-6或图3-7中的第2、3字节,就知道该导出文件字符集为ZHS16GBK。查询数据库中有效的字符集可以使用以下脚本:
col nls_charset_id for 9999
col nls_charset_name for a25
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 10g 的 EXPDP 导出文件,一切则要简单得多,在EXPDP的导出文件开始部分,Oracle 以 XML 格式记录了数据的字符集信息,
-- 以下是一个单表导出文件的头信息。
......
-- 对于传统的 DMP 导出文件,在很多时候,当进行导入操作时,已经离开了源数据库,这时如果目标数据库的字符集和导出文件不一致,
-- 多半就需要进行特殊处理进行转换。最常见的转换发生在从US7ASCII到ZHS16GBK之间。
-- 由于很多数据库最初以US7ASCII字符集存储中文,单纯通过导入是无法完成字符集转换的。对于这种情况,可以通过设置导出字符集为US7ASCII,原样导出数据;
-- 导出后修改导出文件的第二、第三字符,修改0001 为 0354,这样就可以将US7ASCII字符集的数据正确导入到ZHS16GBK的数据库中。
-- 如图3-8所示是一个测试例子,我们可以通过UltraEdit等工具的二进制编辑模式修改导出文件:
......
-- 修改完成之后,可以导入修改后的DMP文件:
E:\nls2> set NLS_LANG=AMERICATION_AMERICA.ZHS16GBK
E:\nls2> imp eygle/eygle file=Sus7ascii-Cus7ascii-exp817.dmp fromuser=eygle touser=eygle table=test
......
-- 通过这种方式,最终中文可以被正常导入ZSH16GBK的数据库:
E:\nls2> sqlplus eygle/eygle
......
SQL> select name.dump(name) from test;
......
-- 另外一种可尝试的方法是使用create database 命令。如果导出文件使用的字符集是US7ASCII,目标数据库的字符集是ZHS16GBK,
-- 就可以使用 create database 的方法来修改,具体操作如下:
SQL> select * from v$nls_parameters;
......
SQL> create database character set us7ascii;
create database character set us7ascii
*
ERROR at line 1:
ORA-01031: insufficient privileges
SQL> select * from v$nls_parameters;


-- 然后可以导入数据:
E:\>nls2> set nls_lang=AMERICAN_AMERICA.US7ASCII
E:\>nls2> imp eygle/eygle file=Su7ascii-Cus7ascii.dmp fromuser=eygle touser=eygle
......
-- 查询数据库:
E:\nls2> sqlplus eygle/eygle
......
SQL> select * from test;
-- 当发出“create database character set us7ascii;”命令时,数据库v$nls_parameters中的字符集设置随之更改,该参数影响导入进程,
-- 更改后可以正确导入数据,重起数据库后,该设置恢复。
-- 提示
-- v$nls_parameters 来源于x$nls_parameters,该动态性能视图影响导入操作;而nls_database_parameters来源于prop$数据表,影响数据存储。
-- 以上方法只应该在不得已的情况下使用,其本质是欺骗数据库,强制导入数据,但是可能会损失元数据。如果要确保数据的完整性,应该使用csscan扫描数据库,
-- 找出所有不兼容的字符,然后通过编写相应的脚本代码,在转换之后进行更新,确保数据的正确性。
-- 简单看一下csscan的使用。要使用csscan之前,需要以sys用户身份创建相应数据字典对象:
E:\nls2> sqlplus "/ as sysdba"
.....
SQL> select instance_name from v$instance;
SQL> @?/rdbms/admin/csminst.sql
......
-- 这个脚本创建相应用户(cmsig)及数据字典对象,扫描信息会记录在相应的数据字典表里。可以在命令行调用这个工具对数据库进行扫描:
E:\nls2> csscan FULL=Y FROMCHAR=ZHS16GBK TOCHAR=US7ASCII LOG=US7check.log CAPTURE=Y ARRAY=1000000 PROCESS=2
-- 然后可以检查输出的日志来查看数据库扫描情况:
......
-- 不能转换的数据将会被记录下来,然后可以根据这些信息在转换之后,对数据进行相应的更新,确保转换无误。
-- 3.7 乱码的产生 ( P105 )
-- 最后我们来讨论一下乱码的产生。通常在现实环境中,存在3个字符集设置:
-- *(1) 客户端应用字符集(Client Application Character Set);
-- *(2) 客户端NLS_LANG参数设置;
-- *(3) 服务器端,数据库字符集(Character Set)设置。
-- 由于一个字符在客户端应用(如SQLPLUS、CMD、NOTEPAD等)中以怎样的字符显示取决于客户端操作系统,客户端能够显示怎样的字符,我们就可以在应用中录入这些字符。
-- 至于这些字符能否在数据库中正常存储,就和另外的两个字符集设置紧密相关了。
-- 在传输过程中,客户端NLS_LANG主要用于进行转换判断。如果NLS_LANG等于数据库字符集,则不进行任何转换直接把字符插入数据库;
-- 如果不同则进行转换,转换主要有两个任务:
-- *(1) 如果存在对应关系,则把相应二进制编码经过映射后(这一步映射以后,所代表的字符可能发生转换)传递给数据库。
-- *(2) 如果不存在对应关系,则传递一个替换字符(不同平台的替换字符各不相同,最常见的替换字符是“?”)。
-- 数据库字符集,在和客户端NLS_LANG不同时,会对经过NLS_LANG转换的字符进一步处理:对于?(即不存在对应关系的字符)直接以?形式存放入数据库,
-- 对于其他字符,在NLS_LANG和数据库字符集之间进行转换后存入。
-- 下面来看一下最为常见的字符集及乱码的产生。
-- *1) 当NLS_LANG字符集与数据库字符集不同
-- 当NLS_LANG字符集与数据库字符集不同,且NLS_LANG不同于客户端字符集设置时,存在以下两种可能。
-- *(1) 客户端输入的字符在NLS_LANG中没有对应的字符,这时无法转换,NLS_LANG使用替换字符集替代这些无法映射的字符(这一步转换在TTS中完成),
--      在很多字符集中之个替代字符就是“?”。
-- *(2) 当客户端的字符在NLS_LANG中对应了不同的字符时,传递给数据库以后发生转换,存储的是字符,但是已经失去了原数据,数据库中的字符不再代表客户端的输入。
--      而且这个过程不可逆,这也就是为什么很多时候在客户端输入的是正常的编码,而查询之后会得到未知字符的原因。
......
-- 可以用我们熟悉的字符集做一个简单的测试(测试环境是客户端代码点对应中文18030字符集,NLS_LANG设置为US7ASCII字符集,
-- 数据库CHARACTER SET为ZHS16GBK)。
C:\> set NLS_LANG=AMERICAN_AMERICA.US7ASCII
C:\> sqlplus eygle/eygle
SQL> insert into test values(1,'测试');
SQL> select name, dump(name) from test;
-- 这时发现,查询出来的是混乱的字符,把这些字符转换为二进制就是:
......
-- 来看正确的存储:
C:\> set nls_lang=AMERICAN_AMERICA.ZHS16GBK
C:\> sqlplus eygle/eygle
SQL> insert into test values(1,'测试');
SQL> column dump(name) for a40
SQL> column name for a20
SQL> select name, dump(name) from test;


NAME                 DUMP(NAME)
-------------------- ----------------------------------------
测试                 Typ=1 Len=6: 230,181,139,232,175,149


-------------------------------------------
vi /etc/sysconfig/i18n
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
-------------------------------------------
-- *2) NLS_LANG和数据库字符集相同时:
-- 在这种情况下,数据库端对客户端传递过来的编码不进行任何转换(这样可以提高性能),直接存储进入数据库,那么这个时候就存在和上面同样的问题,
-- 如果客户端传递过来的字符集在数据库中有正确的对应就可以正确存储,如果没有,就会被替换字符转换成,乱码就这样产生了。
......
-- 来看一个简单的测试(测试环境是客户端代码点对应中文 18030 字符集,客户端 NLS_LANG为US7ASCII,数据库字符集为US7ASCII)。
-- 我们知道这个时候存入的数据,数据库不会进行任何转换,在以下的测试中,看到中文在US7ASCII字符集下得以正确显示。
C:\> set nls_lan=AMERICAN_AMERICA.US7ASCII
C:\> sqlplus eygle/eygle
.....
SQL> insert into test values('测试');
SQL> commit;


SQL> select * from test;


SQL> col dump(name) for a30
SQL> select name, dump(name) from test;


......


SQL> select * from nls_database_parameters;


......


 “靠”字的困惑 ( P109 )


......


-- *(1) 客户端应用字符集(Client Application Character Set)。测试客户端应用使用命令行工具(cmd.exe),
--      这个工具的字符集决定查询结果在终端上的输出显示,当前命令行工具的字符代码页为936,对应的是GBK字符集,如图3-11所示。
D:\> cmd


D:\> chcp


-- *(2) 客户端NLS_LANG参数设置。为了测试异常情况,设置NLS_LANG为AMERICAN_AMERICA.WE8ISO8859P1:
D:\> set NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1


-- *(3) 服务器端,数据库字符集(Character Set)设置。其数据库的字符集为ZHS16GBK。


-- 首先在数据库上创建一个测试表,存储一点中文数据:
SQL> create table tcharset (name varchar2(40));


SQL> insert into tcharset values('循序渐进深入浅出');


-- 然后在客户端WE8ISO8859P1字符集下执行查询:
D:\> set NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1


D:\> sqlplus eygle/eygle@eygle


......


scott@SZTYORA> select * from tcharset;


NAME
----------------------------------------
靠靠靠靠


-- 现在我们看到8个汉字被转换成4个“靠”字输出显示?这是怎么回事呢?


-- 我们知道,Oracle 数据库服务器是传输代码给客户端的,数据本身不存在问题,编码会原样传输到客户段:
SQL> select name, dump(name) from tcharset;


NAME         DUMP(NAME)
------------ -------------------------------------------------------------------------------------------------------------
靠靠靠靠     Typ=1 Len=24: 229,190,170,229,186,143,230,184,144,232,191,155,230,183,177,229,133,165,230,181,133,229,135,186


-- 那么可以确认存在问题的只是中间发生的转换环节。由于WE8ISO8859P1是8位的单Byte编码方案,所以中文汉字编码在其中不存在对应关系,
-- 也就是无法转换,此时WE8ISO8859P1字符集会使用一个替换字符来代替中文,这个替换字符是“ ”,也就是一个倒过来的“?”,不同字符集的替换字符,
-- 我们可以通过Locale Builder工具打开字符文件查看,如图3-12所示。


......


-- 注意这个特殊字符的编码为BF,那么也就是说,如果无法转换ZHS16GBK的8个中文字,WE8ISO8859P1将使用8个“ ”来替换,也就是说经过替换之后,
-- 我们有了8个BF的编码,那么我们再来看看8个BF在客户端的GBK字符集里代表了什么:


-- 通过微软网站上的936代码页我们可以找到如图3-13所示的图表。


......


-- 提示
-- 936代码页的网址链接为 http://www.microsoft.com/globaldev/reference/dbcs/936.htm 。


-- 从图3-13中可以看到,其中BFBF正好代表汉字“靠”,于是8个BF最后展现出来就变成了4个“靠”字。
-- 也就可以通过ZHS16GBK字符集文件来找到这个编码,再者是一致的,如图3-14所示。


......


-- 这也就是不同字符集、应用之间转换导致的字符集问题。


自定义字符的使用 ( P112 )
-- 很多时候,需要存储的字符可能在数据库的字符集中并不存在,这时候我们就可以通过客户端的“True Type造字程序”来对空闲代码点进行自定义字符的创建。


-- 在Windows上,单击“开始”---> “运行” ---> 输入“eudcedit”命令,可以启动造字程序,
-- 然后用造字程序在字符集ChineseGBK下使用代码点AAA1创建一个新字进行测试,如图3-15所示。


......


 更改字符集的内部方式 ( P113 )
-- 前面曾经提到,通过修改pops$的方式更改字符集在Oracle 7之后是一种极其危险的方式,应该尽量避免。我们又知道,
-- 通过ALTER DATABASE CHARACTER SET更改字符集虽然安全可靠,但是有严格的子集和超集和超集的约束,实际上很少能够用到这种方法。


-- 除了前面提到的几种方法外,Oracle还存在另外一种更改字符集的方式:通过隐含的内部命令强制修改字符集。


-- 当使用模板的种子数据库创建数据库时,在创建脚本中可以看到这样的一系列命令:
alter system enable restricted session;
alter database "eygle" open resetlogs;
alter database rename global_name to "eygle";
ALTER TABLESPACE TEMP ADD TEMPFILE 'C:\oracle\oradata\eygle\TEMP01.DBF' SIZE 20480K REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED;
select tablespace_name from dba_tablespaces where tablespace_name='USERS';
select sid, program, serial#, username from v$session;
alter database character set INTERNAL_CONVERT ZHS16GBK;
alter database nation character set INTERNAL_CONVERT AL16UTF16;
alter user sys identified by "&&sysPassword";
alter user system identified by "&&systemPassword";
alter system disable restricted session;


-- 在这里面,可以看到这样的两条重要的、Oracle非公开的命令:
alter database character set INTERNAL_CONVERT ZHS16GBK;
alter database national character set INTERNAL_CONVERT AL16UTF16;


-- 如果检查警告日志文件,可以发现相关更改操作的痕迹:
alter database character set INTERNAL_CONVERT ZHS16GBK
Updating character set in controlfile to ZHS16GBK


......


-- 在使用这个命令时,Oracle会跳过所有子集及超集的检查,在任意字符集之间进行强制转换,所以,使用这个命令时你必须十分小心,并必须清楚这一操作会带来的风险。


-- 之前讲过的内容仍然有效,可以使用csscan扫描整个数据库,如果在转换的字符集之间确认没有严重的数据损坏,或者可以使用有效的方式更改,
-- 就可以使用这种方式进行转换。


-- 这个内部命令的用户引用格式如下:
alter database character set INTERNAL_USE ZHS16CGB231280;


-- 来看一下具体的操作过程及Oracle的内部操作:
SQL> shutdown immedaite;


SQL> STARTUP MOUNT;


SQL> ALTER SYSTEM ENABLE RESTRICTED SESION;


SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;


SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;


SQL> ALTER DATABASE OPEN;


SQL> alter session set events '10046 trace name context forever,level 12'


SQL> alter database character set INTERNAL_USE ZHS16CGB231280


-- 这时警告日志文件中的记录了如下信息:
......


alter database character set INTERNAL_USE ZHS16CGB231280
Updating character set in controlfile to ZHS16CGB231280


......


-- 格式化 10046 跟踪文件,得到以下信息(摘要):


......


-- 可以看到这个过程和之前ALTER DATABASE CHARACTER SET操作的内部过程是完全相同的,
-- 也就是说INTERNAL_USE提供的帮助就是使Oracle数据库绕过了子集与超集的校验。


-- 这一方法在某些方面是有用处的,比如测试;但应用于产品环境时就应该格外小心,除了你以外,没有人会为此带来的后果负责!


-------------------------------------


ORA-29275: 部分多字节字符


-------------------------------------