解决Multibyte character error一例(续)

| No Comments | No TrackBacks

"解决Multibyte character error一例"这篇文章里,我最后用到的解决方法是set NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1,有同事看到这篇文章后问我为什么要这么做?原因是什么?

我这里做一下说明,之所以有了上述解决方法是因为我曾经看到227330.1里有这样一段话"Files made on Unix systems (using vi for example) are most of the time WE8ISO8859P1 depending on the LOCALE setting or used telnet/ssh config." 

 

下面我以一个例子来说明上述问题:

首先来重现一下问题:

E:\>sqlldr ipra/acca@ipradev control=ATPCO.ctl data=LKTCN081121.bad

 

SQL*Loader: Release 10.2.0.1.0 - Production on 星期二 3 10 12:49:24 2009

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

这里sqlldr实际上是一条数据都没有导入进去。

 

这里的本质原因是因为这里windows客户端默认的NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK,而ANSI编码方式中又没有A5所对应的字符,所以oracle这里报错Multibyte character error

 

WE8ISO8859P1是很常用的西欧字符集,我当时估计里面肯定是有A5的,而且当时我的源数据文件中并没有中文,所以我这里放心的将NLS_LANG设成AMERICAN_AMERICA.WE8ISO8859P1目的就是告诉oracle我这里A5不是ANSI编码,WE8ISO8859P1A5,你帮我在WE8ISO8859P1ZHS16GBK之间做一个转换吧

 

E:\>set NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

 

E:\>sqlldr ipra/acca@ipradev control=ATPCO.ctl data=LKTCN081121.bad

 

SQL*Loader: Release 10.2.0.1.0 - Production on Tue Mar 10 12:59:52 2009

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

Commit point reached - logical record count 2

 

转换后我们来看一下转换后A5变成了什么:

SQL> select substr(oatint,314,1) from owbatptemp;

 

SUBSTR(OATINT,314,1)

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

原来我们待导入的字符是A5,也就是¥

现在导入完成后变成了¥。

ultraEdit看了一下这个¥的16进制码,ultraEdit显示这个¥的16进制码是A3 A4,我们来验证一下      

SQL> select dump(substr(oatint,314,1)) from owbatptemp;

 

DUMP(SUBSTR(OATINT,314,1))

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

Typ=1 Len=2: 163,164

Typ=1 Len=2: 163,164

 

这里的163164就是A3A4

SQL> select to_char(163,'XX') from dual;

 

TO_CHAR(163,'XX')

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

 A3

 

SQL> select to_char(164,'XX') from dual;

 

TO_CHAR(164,'XX')

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

 A4

我们可以很清晰的看到这里实际上是发生了字符集的转换。

 

注意这里如果待导入的源数据中有中文,这种方式就不可以采用!一旦采用,所有的中文都会变成乱码,而且不可逆!原因就不用我说了吧:)

LKTCN081121.bad的最开始插入两个中文字符"崔华",然后再次以同样方式导入,我们来看一下结果:

E:\>sqlldr ipra/acca@ipradev control=ATPCO.ctl data=LKTCN081121.bad

 

SQL*Loader: Release 10.2.0.1.0 - Production on Tue Mar 10 13:16:38 2009

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

Commit point reached - logical record count 2

 

QL> select substr(oatint,1,10) from owbatptemp;

 

SUBSTR(OATINT,1,10)

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

′Ta070006

′Ta070006

0700060842

0700060851

 

好了,我来总结一下:

1WE8ISO8859P1不是unicode字符集,它是ISO西欧字符集之一,它不是ZHS16GBK的超集

2如果待导入的源数据中有中文,就不能采用我上述的解决方式。

No TrackBacks

TrackBack URL: http://dbsnake.com/cgi-bin/mt/mt-tb.cgi/14

Leave a comment