【问题标题】:How do I configure pyodbc to correctly accept strings from SQL Server using freeTDS and unixODBC?如何配置 pyodbc 以使用 freeTDS 和 unixODBC 正确接受来自 SQL Server 的字符串?
【发布时间】:2012-11-29 12:05:17
【问题描述】:

我无法将有效字符串从 MSSQL 服务器获取到 python。我相信某处存在编码不匹配。我相信它在 ODBC 层和 python 之间,因为我能够在 tsql 和 isql 中获得可读的结果。

pyodbc 期望什么字符编码?我需要在链中进行哪些更改才能使其正常工作?

具体示例

这里以一个简化的python脚本为例:

#!/usr/bin/env python
import pyodbc

dsn = 'yourdb'
user = 'import'
password = 'get0lddata'
database = 'YourDb'

def get_cursor():
    con_string = 'DSN=%s;UID=%s;PWD=%s;DATABASE=%s;' % (dsn, user, password, database)
    conn = pyodbc.connect(con_string)
    return conn.cursor()

if __name__ == '__main__':
    c = get_cursor()
    c.execute("select id, name from recipe where id = 4140567")

    row = c.fetchone()
    if row:
        print row

这个脚本的输出是:

(Decimal('4140567'), u'\U0072006f\U006e0061\U00650067')

或者,如果脚本的最后一行更改为:

print "{0}, '{1}'".format(row.id, row.name)

那么结果是:

Traceback (most recent call last):
  File "/home/mdenson/projects/test.py", line 20, in <module>
    print "{0}, '{1}'".format(row.id, row.name)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

使用 tsql 执行相同查询的脚本:

root@luke:~# tsql -S cmw -U import -P get0lddata
locale is "C"
locale charset is "ANSI_X3.4-1968"
using default charset "UTF-8"
1> select id, name from recipe where id = 4140567
2> go
id      name
4140567 orange2
(1 row affected)

以及在 isql 中:

root@luke:~# isql -v yourdb import get0lddata
SQL>  select id, name from recipe where id = 4140567
+----------------------+--------------------------+
| id                   | name                     |
+----------------------+--------------------------+
| 4140567              | orange2                  |
+----------------------+--------------------------+
SQLRowCount returns 1
1 rows fetched

所以我早上一直在做这个工作,上下左右看了看,还没有弄清楚哪里出了问题。

详情

以下是版本详情:

  • 客户端是 Ubuntu 12.04
  • freetds v0.91
  • unixodbc 2.2.14
  • python 2.7.3
  • pyodbc 2.1.7-1(来自 ubuntu 包)和 3.0.7-beta06(从源代码编译)

  • 服务器是 XP 和 SQL Server Express 2008 R2

这里是客户端的几个配置文件的内容。

/etc/freetds/freetds.conf

[global]
    tds version = 8.0
    text size = 64512
[cmw]
    host = 192.168.90.104
    port = 1433
    tds version = 8.0
    client charset = UTF-8

/etc/odbcinst.ini

[FreeTDS]
Description = TDS driver (Sybase/MS SQL)
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
CPTimeout =
CPReuse =
FileUsage = 1

/etc/odbc.ini

[yourdb]
Driver = FreeTDS
Description = ODBC connection via FreeTDS
Trace = No
Servername = cmw
Database = YourDB
Charset = UTF-8

【问题讨论】:

  • 在我继续做这件事的过程中,我现在编译了最新版本的 pyodbc,3.0.7-beta06,但是行为没有改变。

标签: sql-server-2008 unicode pyodbc freetds unixodbc


【解决方案1】:

所以在继续工作之后,我现在将 unicode 字符输入 python。不幸的是,我偶然发现的解决方案就像亲吻你的表弟一样令人满意。

我通过安装 python3 和 python3-dev 包然后用 python3 重建 pyodbc 解决了这个问题。

现在我已经完成了这个,我的脚本现在可以工作了,即使我仍然使用 python 2.7 运行它们。

所以我不知道这样做解决了什么问题,但它现在可以工作,我可以继续我开始的项目。

【讨论】:

  • 不是python版本,是ubuntu的包。 Debian 也有同样的问题。我删除了 debian 的包并通过pip 安装了 pyodbc,一切正常,不需要 python 3。
【解决方案2】:

您是否遇到 BOM(字节顺序标记)问题?如果是这样,也许这个 sn-p 代码会有所帮助:

import codecs
if s.beginswith( codecs.BOM_UTF8 ):
    # The byte string s begins with the BOM: Do something.
    # For example, decode the string as UTF-8

if u[0] == unicode( codecs.BOM_UTF8, "utf8" ):
    # The unicode string begins with the BOM: Do something.
    # For example, remove the character.

# Strip the BOM from the beginning of the Unicode string, if it exists
u.lstrip( unicode( codecs.BOM_UTF8, "utf8" ) )

我在 this page 上找到了 sn-p。

【讨论】:

  • 嗯。我已经阅读了您的答案和链接,但我不确定这是问题所在,或者至少我不知道如何处理它。从字符串 u'\U0072006f\U006e0061\U00650067' 中确实可以看出,每对字母都已交换,但缺少第 7 个字符,而且我看不到 BOM 的迹象。
  • 我真的只是根据错误说它无法“...编码位置 0-2 中的字符,因为它们不在范围内”。对不起,马修。
【解决方案3】:

如果您将pyodbc升级到版本3,问题将得到解决。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-22
    • 2013-05-31
    • 2012-09-09
    • 2019-12-20
    • 2011-02-24
    • 2011-02-23
    • 1970-01-01
    • 2011-05-28
    相关资源
    最近更新 更多