缘由:由于工作原因,需要从SQLServer数据库中同步一部分数据到mongodb中,用于建模,运算。
开发环境:Windows,Python3.5.2
开发工具:pycharm2017.1.4
连接SQLServer所用module:pymssql
目标数据库版本:SQLServer2008 编码为GBK
具体情况:
开始连接数据库的代码如下
# 连接数据库,获取游标
@staticmethod
def get_sql_connect(host, user, password, database, charset):
if host is None or user is None or password is None or database is None:
raise ConnectionError('连接数据库的必要参数为空')
if charset is None:
charset = 'utf8'
sql_conn = pymssql.connect(
host=host,
user=user,
password=password,
database=database,
charset=charset
)
return sql_conn
conn = SynchronizeData.get_sql_connect('.', 'sa', '712604', 'test', 'GB18030')
这里在连接的时候传入charset='GBK',因为目标数据库编码是GBK,在python中如果不带这个参数那么查询出来的中文将会显示乱码。带上这个参数之后一切看起来没毛病,在执行了一段时间之后发现会出现UnicodeDecodeError:'gbk'codec can't decode byte 0x81 in position 18:illegal multibyte sequen这样的异常。当时也google了好久,后来找了个靠谱的方案说是因为GBK的字符不多,于是把GBK换成了GB18030问题得到解决。
但是在导入某个表的时候发现此时GB18030也报了上面类似的异常。定位到数据以后该字段的类型类text,里面存储的是一篇文章,初步估计是里面的内容在python中查询之后转Unicode发生了莫名其妙的错误。此时继续在google上搜索,绝大部分说这个异常的情况都是在python中打开文件,然后解决办法是在打开文件的代码中加上coding='utf-8',然而我在连接数据库的时候不过不带charset这个参数就会发生中文乱码,带了吧,就会发生那个异常。本来都打算把数据导出成excel,然后通过mongodbimport去导入了,奈何数据量有点大,昨天这个导出的过程持续了一天也不过导出了一半不到的数据。
今天早上到公司的时候不死心的又在看这个问题。忽然想试下把该字段的类型改成ntext的形式不知道行不行。(SQLServer中有varchar和nvarchar,text和ntext之分,不知道的请另行百度)。把字段的类型改了还是继续采用上面的连接,发现代码是不报错了,但是该字段中的所有中文却消失了,只留下了数字和符号。这很显然又不行的,于是我试验了下面的代码
# 连接数据库,获取游标
@staticmethod
def get_sql_connect(host, user, password, database):
if host is None or user is None or password is None or database is None:
raise ConnectionError('连接数据库的必要参数为空')
sql_conn = pymssql.connect(
host=host,
user=user,
password=password,
database=database
)
return sql_conn
conn = SynchronizeData.get_sql_connect('.', 'sa', '712604', 'test')
激动人心的事情发生了:中文不乱码了,而且字段中的内容也没丢失。问题到这里似乎就可以解决了。接下来的情况就因人而异了:
在修改表字段的时候发现有的字段有索引,导致修改类型失败。于是问题转变成能不能在查询的时候把类型给替换掉。很显然SQLserver还是可以完成这样的功能的: CAST()
于是把我查询的select * from table 改成 select cast(中文内容的字段 as ntext) from table (如果该字段是varchar则 as后面是 nvarchar),问题到这才算完美解决