快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

字符集问题的初步探讨

4. 导入导出及转变

导入导出是我们常用的一个数据迁移及转化工具,因其导出文件具有平台无关性,所以在跨平台迁移中,最为常用。
在导出操作时,异常重要的是客户端的字符集设置,也就是客户端的NLS_LANG设置。
NLS_LANG参数由以下部分组成:

NLS_LANG=<Language>_<Territory>.<Clients Characterset>

NLS_LANG各部分含义如下:
LANGUAGE指定:
-Oracle消息使用的语言
-日期中月份和日显示
TERRITORY指定
-货币和数字格式
-地区和计算星期及日期的习惯
CHARACTERSET:
-控制客户端应用程序使用的字符集
通常设置或者等于客户端(如Windows)代码页
或者对于unicode应用设置为UTF8
在Windows上查看当前系统的代码页可以使用chcp命令:

E:>chcp
活动的代码页: 936

代码页936也就是中文字符集 GBK,在Microsoft的官方站点上,我们可以遭到关于936代码页的详细编码规则,请参考以下链接:

http://www.microsoft.com/globaldev/reference/dbcs/936.htm
我们看一个简朴的测试,来了解一下这几个参数的作用:

E:>set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

E:>sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on 星期六 11月 1 22:51:59 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

连接到:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL> select sysdate from dual;

SYSDATE
----------
01-11月-03

已选择 1 行。

SQL> exit
从Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production中断开

E:>set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

E:>sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Sat Nov 1 22:52:24 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL> select sysdate from dual;

SYSDATE
---------
01-NOV-03

1 row selected.

SQL>


查看客户端NLS_LANG设置可以使用以下方式:
Windows使用:


echo %NLS_LANG%
如:
E:>echo %NLS_LANG%
AMERICAN_AMERICA.ZHS16GBK


Unix使用:

env|grep NLS_LANG
如:
/opt/oracle>env|grep NLS_LANG
NLS_LANG=AMERICAN_CHINA.ZHS16GBK

Windows客户端设置,可以在注册表中更改NLS_LANG,详细键值位于:
HKEY_LOCAL_MACHINESOFTWAREORACLEHOMExx
xx指存在多个ORACLE_HOME时系统编号。


导入和导出是客户端产品,同SQL*PLUS和Oralce Forms相同,因此,使用EXP/IMP工具将按照NLS_LANG定义的方法转变字符集。
导出使用的字符集将会记录在导出文件中,当文件导入时,将会检查导出时使用的字符集设置,假如这个字符集不同于导入客户端的NLS_LANG
设置,字符集将根据导入客户端NLS_LANG设置进行转变,假如必要,在数据插入数据库之前会进行进一步转变。
通常在导出时最好把客户端字符集设置得和数据库端一样,这样可以避免在导出时发生不必要的数据转变,导出文件将和数据库具有一样的字符集。
即使将来会把导出文件导入到不同字符集的数据库中,这样做也可以把转变延缓至导入时刻。
当进行数据导入时,主要存在以下两种情况:
1.源数据库和目标数据库具有一样字符集设置
这时,只需要设置NLS_LANG等于数据库字符集即可导入(前提是,导出使用的是和源数据库一样字符集,即三者一样)
2.源数据库和目标数据库字符集不同
假如我们导出时候使用的NLS_LANG是和源数据库一样的字符集,那么导入时就可以设置客户端NLS_LANG等于导出时使用的字符集,这
样转变只发生在数据库端,而且只发生一次。
例如:
假如进行从WE8MSWIN1252到UTF8的转变
1)使用NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252导出数据库。
这时创建的导出文件包含WE8MSWIN1252的数据
2)导入时使用NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252
这时转变仅发生在insert数据到UTF8的数据库中。
以上假设的转变只在目标数据库字符集是源数据库字符集的超集时才能转变。假如不同,一般就需要进行一些特别的处理。
我们简朴看一下导入的转变过程(以Oracle8i为例):
1.确定导出数据库字符集环境
通过读取导出文件头,可以获得导出文件的字符集设置
2.确定导入session的字符集,即导入Session使用的NLS_LANG环境变量
3.IMP读取导出文件
读取导出文件字符集ID,和导入进程的NLS_LANG进行比较
4.假如导出文件字符集和导入Session字符集一样,那么在这一步骤内就不需要转变
假如不同,就需要把数据转变为导入Session使用的字符集。
然而这种转变只能在单byte字符集之间进行。
我们看一个测试:

E:nls2>set NLS_LANG=AMERICAN_AMERICA.US7ASCII

设置导入session NLS_LANG为US7ASCII

E:nls2>e:oracleora8ibinimp eygle/eygle file=Sus7ascii-Cus7ascii-exp817.dmp fromuser=eygle touser=eygle tables=test

这个导出文件是从US7ASCII数据库导出,导出客户端NLS_LANG也是US7ASCII

Import: Release 8.1.7.1.1 - Production on Fri Nov 7 00:59:22 2003

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production
With the Partitioning option
JServer Release 8.1.7.1.1 - Production

这时导入,在DMP文件和NLS_LANG之间不需要进行字符集转变。

Export file created by EXPORT:V08.01.07 via conventional path
import done in US7ASCII character set and ZHS16GBK NCHAR character set
import server uses ZHS16GBK character set (possible charset conversion)
export server uses UTF8 NCHAR character set (possible ncharset conversion)
. . importing table "TEST" 2 rows imported
Import terminated successfully without warnings.


5.对于多Byte字符集的导入(如:UTF8)
需要设置导入Session字符集和导出字符集一样
否则就会碰到:IMP-16 "Required character set conversion (type %lu to %lu) not supported" 错误。
:
E:nls2>set NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

导入Session字符集设置为ZHS16GBK
导入US7ASCII的导出文件

E:nls2>e:oracleora8ibinimp eygle/eygle file=Sus7ascii-Cus7ascii-exp817.dmp fromuser=eygle touser=eygle

Import: Release 8.1.7.1.1 - Production on Fri Nov 7 00:38:55 2003

(c) Copyright 2000 Oracle Corporation. All rights reserved.

Connected to: Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production
With the Partitioning option
JServer Release 8.1.7.1.1 - Production

IMP-00016: required character set conversion (type 1 to 852) not supported
IMP-00000: Import terminated unsuccessfully

在从导出文件US7ASCII到导入 NLS_LANG设置为ZHS16GBK的过程中,不支持单Byte字符集向多Byte转变,报出以上错误。


6.导入Session字符集应该是导出字符集的超级,否则,专有的字符将难以准确转变。
7.当数据转变为导入Session字符集设置以后,假如导入Session字符集不同于导入数据库字符集,这时还需要最后一步转变,这要求导入数据库字符
集是导入session字符集的超级,否则某些专有字符将不能正常转变。
我们继承看上面的两个过程,这里有这样两个原则:
1.假如NLS_LANG的设置和数据库一样,那么数据(在传输过程中当然是2进制码)不经过转变就直接插入数据库中。
2.假如NLS_LANG的设置和数据库不同,那么数据需要转变后才能插入数据库中。
我们再回头来看上面的第一个例子:
:
Export file created by EXPORT:V08.01.07 via conventional path
import done in US7ASCII character set and ZHS16GBK NCHAR character set
import server uses ZHS16GBK character set (possible charset conversion)
export server uses UTF8 NCHAR character set (possible ncharset conversion)
. . importing table "TEST" 2 rows imported
Import terminated successfully without warnings.

这时候经过第一步转变后的数据,US7ASCII到ZHS16GBK丢失首位,原样插入数据库,我们看到这时数据库中存放的就是错误的字符(在后面部分我们做了具体的转变):

E:nls2>sqlplus eygle/eygle

SQL*Plus: Release 9.2.0.4.0 - Production on Fri Nov 7 00:35:39 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.


Connected to:
Oracle8i Enterprise Edition Release 8.1.7.1.1 - Production
With the Partitioning option
JServer Release 8.1.7.1.1 - Production

SQL> select * from test;

NAME
--------------------
2bJT
test


在Oracle9i中,以上情况略有不同。
返回类别: 教程
上一教程: 编写安全的SQL SERVER扩展存储过程
下一教程: 如何提取除最新十条记录之外的所有记录?

您可以阅读与"字符集问题的初步探讨"相关的教程:
· MYSQL5.0的字符集设置问题:支持中文
· SQL2000治理SQL7服务器出现TIMEOUT问题的解决
· 实用的MYSQL中文问题的解决方案
· MySQL 字符集支持
· 关于MYSQL 4.1语言问题的完美解决方式
    微笑服务 优质保证 索取样品