我正在使用 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
我从31e2fae4adbf1b2af1726e5668a3414cf46b454f
抓取了pyodbc修订版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的包装函数
这不是很多,是吗?
答案 0 :(得分:21)
我记得使用odbc驱动程序有这种愚蠢的问题,即使那时它是java + oracle组合。
核心问题是odbc驱动程序在将查询字符串发送到数据库时显然会对其进行编码。即使该字段是Unicode,并且如果您提供Unicode,在某些情况下它似乎并不重要。
您需要确保驱动程序发送的内容与数据库(不仅是服务器,还包括数据库)具有相同的编码。否则,当然你会得到时髦的角色,因为客户端或服务器在编码/解码时会混合起来。您是否知道服务器用作解码数据的默认字符集(代码点为MS)?
例如,请参阅that MS page。对于Unicode字段,排序规则仅用于定义列中的排序顺序,不是以指定数据的存储方式。
如果您将数据存储为Unicode,则有一种独特的方式来表示它,这就是Unicode的目的:无需定义与您将要使用的所有语言兼容的字符集:)
这里的问题是“当我向不是 Unicode的服务器提供数据时会发生什么?”。例如:
从服务器的角度来看,所有这三个字符串只是一个字节流。服务器无法猜测您对其进行编码的编码。这意味着如果您的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')
试试吧。好有趣。解码后的字符串应该是“嘿,我的名字是André”,但是“嘿,我的名字是Andrテゥ”。 é被日语テゥ取代
因此我的建议是:您需要确保pyodbc能够以Unicode直接发送数据。如果pyodbc无法做到这一点,你将得到意想不到的结果。
我在Client to Server方式中描述了这个问题。但是,当从服务器回传到客户端时,会出现同样的问题。如果客户端无法理解Unicode数据,您可能会遇到麻烦。
实际上,FreeTDS为您处理事情并将所有数据转换为UCS2 unicode。 (Source)。
/etc/freetds/freetds.conf
)如果您将UTF-8数据传递给pyodbc,我希望您的应用程序能正常工作。事实上,正如这个django-pyodbc ticket状态,django-pyodbc以UTF-8与pyodbc通信,所以你应该没问题。
然而,cramm0表示FreeTDS 0.82并非完全无错,并且0.82与官方修补的0.82版本之间存在显着差异here。您应该尝试使用已修补的FreeTDS
已修改:删除旧数据,这与FreeTDS无关,但仅与Easysoft商业odbc驱动程序相关。遗憾。
答案 1 :(得分:2)
我使用UCS-2与SQL Server交互,而不是UTF-8。
更正:我更改了.freetds.conf条目,以便客户端使用UTF-8
tds version = 8.0
client charset = UTF-8
text size = 32768
现在,绑定值适用于UTF-8编码的字符串。 驱动程序在用于存储在数据服务器端的UCS-2和提供给客户端的UTF-8编码字符串之间进行透明转换。
这是在Solaris 10上运行Python 2.5和FreeTDS freetds-0.82.1.dev.20081111和SQL Server 2008的pyodbc 2.0
import pyodbc test_string = u"""Comment ça va ? Très bien ?""" print type(test_string),repr(test_string) utf8 = 'utf8:' + test_string.encode('UTF-8') print type(utf8), repr(utf8) c = pyodbc.connect('DSN=SA_SQL_SERVER_TEST;UID=XXX;PWD=XXX') cur = c.cursor() # This does not work as test_string is not UTF-encoded try: cur.execute('INSERT unicode_test(t) VALUES(?)', test_string) c.commit() except pyodbc.Error,e: print e # This one does: try: cur.execute('INSERT unicode_test(t) VALUES(?)', utf8) c.commit() except pyodbc.Error,e: print e
以下是测试表的输出(我通过Management Studio手动输入了一堆测试数据)
In [41]: for i in cur.execute('SELECT t FROM unicode_test'): ....: print i ....: ....: ('this is not a banana', ) ('\xc3\x85kergatan 24', ) ('\xc3\x85kergatan 24', ) ('\xe6\xb0\xb4 this is code-point 63CF', ) ('Mich\xc3\xa9l', ) ('Comment a va ? Trs bien ?', ) ('utf8:Comment \xc3\xa7a va ? Tr\xc3\xa8s bien ?', )
我能够通过“编辑前200行”对话框将一些unicode代码点直接放入Management Studio的表中,然后输入unicode代码点的十六进制数字,然后按Alt-X
答案 2 :(得分:1)
尝试绑定unicode参数时遇到了同样的问题: '[HY004] [FreeTDS] [SQL Server]无效的数据类型(0)(SQLBindParameter)'
我通过将freetds升级到版本0.91来解决它。
我使用pyodbc 2.1.11。我不得不应用this补丁来使其与unicode一起使用,否则偶尔会出现内存损坏错误。
答案 3 :(得分:0)
你确定INSERT导致问题无法阅读吗? 在pyodbc Problem fetching NTEXT and NVARCHAR data上打开了一个错误。