奇怪的问题
最近在做数据加载的时候,遇到一个问题,就是来源系统teradata的一张表,使用了latin 字符集来存储中文。不仅如此,还在部分字段里增加了欧元符(€)。如果通过sqoop来传输数据的时候,client_charset无论设置为gbk,还是gb18030,欧元符(€)全部变成了问号(?)。
分析
经过查询才知道,欧元符(€)的ascii码,在unicode和non-unicode的场景下,值是不一样的。Non-unicode的情况下,欧元符(€)=0x80。而GBK,GB18030这些字符集里,对于0x80这个ascii码,是没有对应的定义的。
基于以上原理,可以得知,teradata采用latin字符集存储数据时,欧元符(€)就是按0x80进行存储的。而sqoop按照GBK或者GB18030去解释的时候,0x80因为没有定义,全部解释成NULL,显示出来就是?。
那是不是就没有办法了呢?肯定不是。因为使用Teradata Windows客户端来查看数据的时候,欧元符(€)和中文都可以正常显示。Windows是怎么做到这一点的呢?难道Teradata Windows客户端如此智能,能够对欧元符(€)进行特别处理?
其实说穿了很简单,这个是微软公司替大家想了一个方案。既然标准汉字字符集里不包括欧元符(€),那我就做一个包括欧元符(€)的定制化中文字符集不就好了吗。这个字符集就叫windows-936,它不同于标准cp936的地方就在于它多了对0x80的定义。
解决方案
知道了原理,解决方案就简单了。查了一下java支持的字符集 ,找到一个ms936, 说明为Windows Simplified Chinese 。将sqoop jdbc url的charset换成ms936,终于可以看到欧元符(€)和中文完美的同时出现了。