我正在使用 Ubuntu 9.04
我安装了以下软件包版本:
unixodbc and unixodbc-dev: 2.2.11-16build3
tdsodbc: 0.82-4
libsybdb5: 0.82-4
freetds-common and freetds-dev: 0.82-4
我已经配置了/etc/unixodbc.ini
像这样:
[FreeTDS]
Description = TDS driver (Sybase/MS SQL)
Driver = /usr/lib/odbc/libtdsodbc.so
Setup = /usr/lib/odbc/libtdsS.so
CPTimeout =
CPReuse =
UsageCount = 2
我已经配置了/etc/freetds/freetds.conf
像这样:
[global]
tds version = 8.0
client charset = UTF-8
我已获取 pyodbc 修订版 31e2fae4adbf1b2af1726e5668a3414cf46b454f
来自 http://github.com/mkleehammer/pyodbc
并使用“python setup.py install
”安装它
我的本地网络上安装了 Microsoft SQL Server 2000 的 Windows 机器,启动并监听本地 IP 地址 10.32.42.69。我有一个名为“Common”的空数据库。我有用户“sa”,密码为“secret”,拥有完全权限。
我正在使用以下 python 代码来设置连接:
import pyodbc
odbcstring = "SERVER=10.32.42.69;UID=sa;PWD=secret;DATABASE=Common;DRIVER=FreeTDS"
con = pyodbc.connect(s)
cur = con.cursor()
cur.execute('''
CREATE TABLE testing (
id INTEGER NOT NULL IDENTITY(1,1),
name NVARCHAR(200) NULL,
PRIMARY KEY (id)
)
''')
con.commit()
到目前为止,一切都有效。我在服务器上使用了 SQLServer 的企业管理器,新表就在那里。 现在我想在表格中插入一些数据。
cur = con.cursor()
cur.execute('INSERT INTO testing (name) VALUES (?)', (u'something',))
失败了!!这是我得到的错误:
pyodbc.Error: ('HY004', '[HY004] [FreeTDS][SQL Server]Invalid data type
(0) (SQLBindParameter)'
由于我的客户端配置为使用 UTF-8,我想我可以通过将数据编码为 UTF-8 来解决。这行得通,但后来我得到了奇怪的数据:
cur = con.cursor()
cur.execute('DELETE FROM testing')
cur.execute('INSERT INTO testing (name) VALUES (?)', (u'somé string'.encode('utf-8'),))
con.commit()
# fetching data back
cur = con.cursor()
cur.execute('SELECT name FROM testing')
data = cur.fetchone()
print type(data[0]), data[0]
这没有错误,但返回的数据与发送的数据不同!我明白了:
<type 'unicode'> somé string
也就是说,pyodbc 不会直接接受 unicode 对象,但它会将 unicode 对象返回给我!而且编码搞混了!
现在问题来了:
我希望代码在 NVARCHAR 和/或 NTEXT 字段中插入 unicode 数据。当我查询回来时,我想要我插入回来的相同数据。
这可以通过以不同方式配置系统,或者通过使用能够在插入或检索时正确地将数据转换为/从 unicode 的包装函数
这要求不高,是吗?
最佳答案
我记得在使用 odbc 驱动程序时遇到过这种愚蠢的问题,即使当时是 java+oracle 的组合。
核心是 odbc 驱动程序在将查询字符串发送到数据库时显然对其进行了编码。即使该字段是 Unicode,并且如果您提供 Unicode,在某些情况下似乎也无关紧要。
您需要确保驱动程序发送的内容与您的数据库(不仅是服务器,还有数据库)具有相同的编码。否则,您当然会得到时髦的字符,因为客户端或服务器在编码/或解码时会混淆。您对您的服务器用作解码数据的默认字符集(MS 喜欢说的代码点)有任何想法吗?
排序规则与这个问题无关:)
见 that MS page例如。对于 Unicode 字段,排序规则仅用于定义列中的排序顺序,不用于指定数据的存储方式。
如果您将数据存储为 Unicode,则有一种独特的方式来表示它,这就是 Unicode 的目的:无需定义与您将要使用的所有语言兼容的字符集 :)
这里的问题是“当我向服务器提供非 Unicode 的数据时会发生什么?”。例如:
- 当我向服务器发送一个 UTF-8 字符串时,它是如何理解的?
- 当我向服务器发送一个 UTF-16 字符串时,它是如何理解的?
- 当我向服务器发送一个 Latin1 字符串时,它是如何理解的?
从服务器的角度来看,这 3 个字符串都只是一个字节流。服务器无法猜测您对它们进行编码的编码。这意味着如果您的 odbc 客户端最终向服务器发送 bytestrings(编码字符串)而不是发送 unicode 数据,您将遇到麻烦:如果您这样做,服务器将使用预定义的编码(这是我的问题:服务器将使用什么编码?因为它不是猜测,所以它必须是一个参数值),并且如果字符串已使用不同的编码进行编码, dzing,数据将被损坏。
这和在 Python 中做的完全一样:
uni = u'Hey my name is André'
in_utf8 = uni.encode('utf-8')
# send the utf-8 data to server
# send(in_utf8)
# on server side
# server receives it. But server is Japanese.
# So the server treats the data with the National charset, shift-jis:
some_string = in_utf8 # some_string = receive()
decoded = some_string.decode('sjis')
试试吧。好有趣。解码后的字符串应该是“Hey my name is André”,但实际上是“Hey my name is Andrテゥ”。 é 被日文 テゥ
取代因此我的建议是:您需要确保 pyodbc 能够以 Unicode 格式直接发送数据。如果 pyodbc 没有做到这一点,你会得到意想不到的结果。
我以客户端到服务器的方式描述了这个问题。但是当从服务器返回到客户端时,也会出现同样的问题。如果客户端无法理解 Unicode 数据,您可能会遇到麻烦。
FreeTDS 为您处理 Unicode。
实际上,FreeTDS 会为您处理一切并将所有数据转换为 UCS2 unicode。 (Source)。
- 服务器 <--> FreeTDS : UCS2 数据
- FreeTDS <--> pyodbc : 编码字符串,以 UTF-8 编码(来自
/etc/freetds/freetds.conf
)
因此,如果您将 UTF-8 数据传递给 pyodbc,我希望您的应用程序能够正常工作。其实像这样django-pyodbc ticket状态,django-pyodbc 以 UTF-8 与 pyodbc 通信,所以你应该没问题。
FreeTDS 0.82
但是,cramm0表示 FreeTDS 0.82 并非完全没有错误,0.82 与官方修补的 0.82 版本之间存在显着差异,可以找到 here .您可能应该尝试使用修补过的 FreeTDS
已编辑:删除了与 FreeTDS 无关但仅与 Easysoft 商业 odbc 驱动程序相关的旧数据。对不起。
关于python - 在 linux 上使用 pyodbc 在 nvarchar mssql 字段中插入 unicode 或 utf-8 字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/947077/