解决使用Pyodbc向MSSQL插入unicode字符乱码的问题

版权声明:本文为sam的原创文章,转载请添加出处:http://blog.csdn.net/samed https://blog.csdn.net/samed/article/details/50539742

——这个问题烦扰了我将近3个星期。

重要提醒:想看解决方案的直接拖到最后,这中间的过程,急性子的人可以不用看。


问题描述:

现有:

1. unicode字符串:a = "测试" ;

2. 数据库SQL Server 2008表 t(name nvarchar(100))

3. linux主机:CentOS6.7 64bit(run in docker)

4. 驱动及接口:unixODBC2.2.14、FreeTDS0.9.1、pyodbc3.0.10

想要把这个a字符串插入到t表中。

就这么简单。


实际上,这个并不简单,unicode字符串通过pyodbc插入到sqlserver里面的时候,会变成:

?μ?èˉ?


之类的东东,俗称乱码。


问题的详细描述请看我在论坛的发帖:求助:Linux下使用Pyodbc插入数据到MSSQL中文乱码 [问题点数:100分]

CSDN确实不够给力。

只有一条回帖,而且没有啥价值(给点提示和意见都好啊~哭)。

简单的来说,就是,windows下能正常执行的代码,插入中文无压力,到了linux下,就不行了,插入的是乱码。

而且最怪异的是pyodbc用的是freetds的驱动,在freetds里面insert却毫无压力,中文正常到吐。


今晚找了个VPN,把StackOverFlow翻了个遍,终于找到了解决方案。

废话真多(你也觉得是吧)。



参考文献1的问题就和我的描述基本一致,只是,作者的数据库是latin1的env。

投票最多的那个答案嘛,给了我一个提示:

通过FreeTDS进行数据库连接,路径如下:

Python App --1-- pyodbc --2-- FreeTDS --3-- DBServer

而这每一步都有一个coding的问题在。

首先,保证python脚本的coding必须要正确,例如utf-8,这个可以在windows下写好脚本执行尝试一下,确认无误就好。

其次,pyodbc传递给freetds会进行一次转码,怎么转,转成什么,不知道,也没有更多信息或者文档支持和论证这个问题。

最后,FreeTDS会将任何接收到的东西采用UCS2编码的方式转码后传递到数据库,写入。(http://www.freetds.org/userguide/unicodefreetds.htm


所以,如果1、3我都测试通过没有问题,那么症结就在pyodbc转码传递给FreeTDS的问题了。

python不支持UCS2编码,所以没有办法采用这种方式转码,而FreeTDS也不能明文改成这种编码的字符串。

pyodbc的文档非常悲剧,啥都没有,那看看StackOverFlow是否有相关的文献提供支持?

无意中翻阅了文献2和文献3,文献2表示pyodbc的用法嘛,是不建议你通过拼接变量的方式进行赋值的,而是使用“?”表达式(暂且这么称呼吧)来赋值。

例如:

问题描述中的插入语句我原本是写成:

SqlStr = "insert into t(name) values(%s)" % (a)

按照pyodbc的问号表达式的写法,应该写成:

SqlStr = "insert into t(name) values(?)" % (a)

这不是传说中的换汤不换药么?

回答的人轻轻地表示,这样做之后,就能搞定了。

然后捏,然后文献2的作者然并卵地说他自己笨了,原来是系统的语言环境没有设置对。

我就不在意了。

文献3里面,有回答表示:“丫的,你写入nvarchar字段,加个N呀”。

按照他的想法,应该直接这样:

SqlStr = u"insert into t(name) values(N'测试')"

我就兴高采烈屁颠屁颠地试了一下,放屁。


然后二楼就接话了:“孩子,你还年轻,想当年我年轻的时候,用pyodbc的问号表达式的赋值方法,就解决你这个问题了。”

真的么?

果然……



解决方案:

1. 首先你的数据库至少是UTF-8编码的,正常来说,我们大天朝子民,一般都使用 Chinese_PRC_CI_AS

2. python脚本文件本身是UTF-8编码的(在linux下用file命令查看,得到结果:test.py UTF-8 Unicode Java program text

3. python脚本第一行加上文件编码的定义,两种写法均可:(1)# -*-coding:utf-8-*-;(2)# coding:utf-8

4. python脚本中,中文(或者泛称unicode字符串)需要使用如下格式:u'中文'

5. FreeTDS配置需加上 client charset = UTF-8 (不知道加哪里看我的提问贴求助:Linux下使用Pyodbc插入数据到MSSQL中文乱码 [问题点数:100分]

6. 脚本中,涉及到pyodbc insert的语句,采用如下方式执行:

sql = "insert into tpayon_test (name) values (?)"
parameters = (u"中文")
cursor.execute(sql, parameters)


以上6点,缺一不可。

最后兴奋地贴一个图吧:

中文



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

参考文献:

1. using pyodbc on linux to insert unicode or utf-8 chars in a nvarchar mssql field

2. pyODBC and Unicode

3. why insert empty value using pyodbc in Linux environment?

4. pyodbc官方文档




猜你喜欢

转载自blog.csdn.net/samed/article/details/50539742