`
CtripMySQLDBA
  • 浏览: 56421 次
  • 来自: 上海
社区版块
存档分类
最新评论

Linux系统通过python访问SQL SERVER,无法显示数据库内中文的问题

阅读更多

最近遇到几个需求,需要从centos上通过python访问sql server服务器查询数据,本来倒也不是很复杂,通过pyodbc比较顺利地实现了,具体如下:

 

  1. 先直接通过yum安装unixODBC、unixODBC-devel和freetds (pyodbc需要)
  2. 然后源码编译安装pyodbc
  3. 配置/etc/odbcinst.ini,添加连接sql server的数据源信息 (路径按实际情况填写)
[SQL Server]
Description     = FreeTDS ODBC driver for MSSQL
Driver      = /usr/local/freetds/lib/libtdsodbc.so
Setup       = /usr/local/freetds/lib/libtdsS.so
FileUsage       = 1

 配置完成后就可以直接访问sql server数据库进行查询了

#!/usr/bin/env python
#-*- encoding: utf-8 -*-
import pyodbc
conn=pyodbc.connect('DRIVER={SQL Server};SERVER=xxx.xxx.xxx.xxx;port=1433;DATABASE=testdb;UID=user;PWD=password')
cursor=conn.cursor()
cursor.execute("select name from test")
row=cursor.fetchone()
print row[0]

 

然而,还没有高兴多久就发现一个大问题,数据库中存储的中文字符不能正常显示,全部变成了问号。这其实也很正常,因为sql server里面的字符编码不是通用的utf-8(所以说windows上的东西就是难搞啊)。虽然知道原因,但是要解决这个问题却也不是很容易,在对freetds的charset设置和pyodbc连接的charset设置进行各种调整尝试,返回结果也各种encode、decode之后,问号依然是顽强的问号。

 

在被问号折腾了好久快要放弃的时候,终于找到了解决办法。究其根本原因,还是Linux和window系统间的不同字符集问题,这实在是个难翻的墙啊。freetds会做字符集的默认转换,结果就是这个转换导致了中文变问号。解决方法:

  1. 首先,freetds必须源码安装,在编译时指定参数disable-libiconv,禁止自动转换:./configure --enable-msdblib --prefix=/usr/local/freetds --with-tdsver=8.0 --disable-libiconv
  2. 然后,连接数据库时需要指定tds_version参数,版本太低会有问题,我用的是8.0(访问sql server 2008 R2)
  3. 在获取返回结果时,由于sql server内部是gbk编码的,因此需要把结果从gbk进行解码,这样才能在utf8环境中正常显示。
conn=pyodbc.connect('DRIVER={SQL Server};SERVER=xxx.xxx.xxx.xxx;port=1433;DATABASE=testdb;UID=user;PWD=password;TDS_Version=8.0')
cursor=conn.cursor()
cursor.execute("select name from test")
row=cursor.fetchone()
print row[0].decode('gbk')

 

这样,终于成功地把中文正常显示出来了!不过还需要注意,如果中文字符在sql server中是使用unicode方式存储的(nvarchar nchar),那么还是会乱码,不过这个问题也很容易处理,在select的时候进行下转换即可,例如select convert(varchar,name) as name

 

 

 

 

 

5
0
分享到:
评论
2 楼 CtripMySQLDBA 2013-05-13  
martyl 写道
freetds的转换没看懂,是什么转换到了什么,这种转换是否有配置文件中的项可以指定?

另外SQL Server中对Unicode字段编码是UCS-2,确实比较罕见,2012版本开始同时支持UTF-16,还未有支持Linux最常用的UTF-8。想来freetds是专门的SQL Server驱动应该有考虑这点,硬转nvarchar有点不自然。


关于freetds的那个转换动作,官方是这么说明的:
【--disable-libiconv
By default, configure will search your system for an iconv library for use with Microsoft servers (because TDS 7.0 employs Unicode). This switch prevents that search. If no iconv library is used, FreeTDS relies on its built-in iconv emulation, which is capable of converting ISO-8859-1 to UCS-2, sufficient for many applications.

所以按理说,这个动作不会让mssql里面的中文乱码的,但是确实开了禁用参数以后解决了我的问题。这个在配置文件里面没法控制,配置文件里面的charset不管怎么设置(utf8,gbk,cp936等等)都没用,中文依然是问号。
另外,关于nvarchar的UCS-2编码问题,freetds确实应该是支持的(上面的官方说明上也有提到),但是我在pyodbc返回的结果就是没办法正确解码,所以还是硬转下nvarchar比较容易。
鉴于我毕竟不是专业的python开发,只能尽量做到满足自己的需求,如果大家有好的方法请不吝分享下,欢迎多多指教
1 楼 martyl 2013-05-12  
freetds的转换没看懂,是什么转换到了什么,这种转换是否有配置文件中的项可以指定?

另外SQL Server中对Unicode字段编码是UCS-2,确实比较罕见,2012版本开始同时支持UTF-16,还未有支持Linux最常用的UTF-8。想来freetds是专门的SQL Server驱动应该有考虑这点,硬转nvarchar有点不自然。

相关推荐

Global site tag (gtag.js) - Google Analytics