含有汉字由ZHS16GBK数据库导入到AL32UTF8的数据库

2017-07-27

对英文,在al32utf8中仍然和zhs16gbk一样用1个字节表示,因此导入固定长度英文字符数据时不会出错。zhs16gbk 数据库中每个字符占用2字节,al32utf8 数据库中每个字符占用3字节。

对中文:例如在字符集为zhs16gbk 数据库中创建表时指定字段 val char(15),该字段含有数据 ‘阿里云计算公司’在字符集为zhs16gbk 数据库中占用14个字节,而在字符集为al32utf8 数据库中占用21个字节大于 char(15)所指定的长度15.此时导入数据就会失败。

实例1:

IMP-00019: row rejected due to ORACLE error 12899
IMP-00003: ORACLE error 12899 encountered
ORA-12899: value too large for column "CORE"."CUSTOMER"."PHONE_NUMBER" (actual: 23, maximum: 20)

 

1、
create public database link crm02 connect to crm identified by 123456 using ‘DB02′;
create  table as select * from t1@db1 where 1=2;
insert into t1 select * from table1@db1;
2、expdp yang/yang tables=chart directory=dumpdir  dumpfile=zhs16gbk.dmp
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
.bash_profile 文件里已经声明了,这里是强调一下。

impdp yang/yang tables=chart directory=dumpdir dumpfile=zhs16gbk.dmp log=zhs16gbk_to_al32utf8.log

 

小结:字符集子集向其超集转换是可行的,如此例 ZHS16GBK转换为AL32UTF8。
导出使用的字符集将会记录在导出文件中,当文件导入时,将会检查导出时使用的字符集设置,如果这个字符集不同于导入客户端的NLS_LANG
设置,字符集将根据导入客户端NLS_LANG设置进行转换,如果必要,在数据插入数据库之前会进行进一步转换。
通常在导出时最好把客户端字符集设置得和数据库端相同,这样可以避免在导出时发生不必要的数据转换,导出文件将和数据库具有相同的字符集。
即使将来会把导出文件导入到不同字符集的数据库中,这样做也可以把转换延缓至导入时刻。

 

当进行数据导入时,主要存在以下两种情况:
1.源数据库和目标数据库具有相同字符集设置
这时,只需要设置NLS_LANG等于数据库字符集即可导入(前提是,导出使用的是和源数据库相同字符集,即三者相同)

2.源数据库和目标数据库字符集不同
如果我们导出时候使用的NLS_LANG是和源数据库相同的字符集,那么导入时就可以设置客户端NLS_LANG等于导出时使用的字符集,这样转换只发生在数据库端,而且只发生一次。

例如:
如果进行从ZHS16GBK到UTF8的转换
1)使用NLS_LANG=AMERICAN_AMERICA.ZHS16GBK导出数据库。
这时创建的导出文件包含ZHS16GBK的数据
2)导入时使用NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
这时转换仅发生在insert数据到UTF8的数据库中。

以上假设的转换只在目标数据库字符集是源数据库字符集的超集时才能转换。

 

 

例如2:
src
NLS_LANG=AMERICAN_CHINA.ZHS16GBK

ORA-39087: directory name DUMPDIR is invalid

1. 创建directory(在sqlplus中进行创建)

SQL> create or replace directory dpdata1 as '/home/oracle';
SQL> grant read,write on directory dpdata1 to scott;

删除directory:

drop directory wsj_obj_name;

select * from dba_directories;
expdp "user/1234" tables=customer directory=DPDATA1  dumpfile=customer_zhs16gbk.dmp

 

impdp emr/emr@emr SCHEMAS=emr DUMPFILE=expdp.dmp DIRECTORY=data_pump_dir  remap_schema=scott:abc ;
impdp server/123456 DUMPFILE=customer_zhs16gbk.dmp DIRECTORY=DPDATA1 tables=customer remap_data=user1.customer:user2.customer;
REMAP_DATA=EMP.EMPNO:REMAPPKG.EMPNO
ORA-39166: Object user1.CUSTOMER was not found.

实例3:

通过ZHS16GBK和AL32UTF8字符编码分析exp/imp

 

虽然导出客户端设置了不步的编码,但是导出的文件大小相等

export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

exp hr/xifenfei file=/tmp/xifenfei_AL32UTF8.dmp log=/tmp/xifenfei.log tables=xifenfei
exp hr/xifenfei file=/tmp/xifenfei_ZHS16GBK.dmp log=/tmp/xifenfei.log tables=xifenfei
ll *.dmp
-rw-r--r-- 1 oracle oinstall 16384 12-21 14:07 xifenfei_AL32UTF8.dmp
-rw-r--r-- 1 oracle oinstall 16384 12-21 14:38 xifenfei_ZHS16GBK.dmp
--通过比较知道,不同客户端编码,导出的数据内容相同,
--都是一个汉字对应两个字节(说明是按照服务端编码导出)

 

修改列长度,导入成功alter table xifenfei modify name varchar2(9);

无论源端客户端使用何种编码导出,目标端使用何种编码导入(仅限我这里说的AL32UTF8和ZHS16GBK),如果客户端编码是ZHS16GBK,验证数据的时候,可以省略掉设置编码的过程。

 

--导入报错后,登录数据库,修改列长度,因为目标端数据库编码是AL32UTF8,
--1个汉字占用3个字节修改列的程度满足错误提示的最大程度。

试验总结
1.当源端字符编码为ZHS16GBK,目标端编码为AL32UTF8,客户端随便为其中的一种编码,迁移数据不会出现乱码,但是会出现列长度不够现象。反过来不行,因为utf8中的部分字符转换到gbk中肯定会不支持
2.设置了源端客户端编码,仅仅是导出来的dmp文件头部有编码字符标示不一样,存储数据还是按照服务端存储
3.打破神话,exp/imp导入要不乱码,导出和导入的客户端编码要一致

 

分类:数据库 | 标签: |

相关日志

评论被关闭!