代码之家  ›  专栏  ›  技术社区  ›  nosklo

在linux上使用pyodbc在nvarchar mssql字段中插入unicode或utf-8字符

  •  23
  • nosklo  · 技术社区  · 16 年前

    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

    我有一台窗户机器 微软SQL Server 2000 安装在我的本地网络上,打开并监听本地ip地址10.32.42.69。我创建了一个名为“Common”的空数据库。我拥有用户“sa”和密码“secret”,具有完全权限。

    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()
    

    一切 现在我想在表中插入一些数据。

    cur = con.cursor()
    cur.execute('INSERT INTO testing (name) VALUES (?)', (u'something',))
    

    失败了!!这是我得到的错误:

    pyodbc.Error: ('HY004', '[HY004] [FreeTDS][SQL Server]Invalid data type 
    (0) (SQLBindParameter)'
    

    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数据。当我回查询时,我想要回插入的相同数据。

    这要求不高,是吗?

    4 回复  |  直到 16 年前
        1
  •  22
  •   Community Mohan Dere    5 年前

    我记得在使用odbc驱动程序时遇到过这种愚蠢的问题,即使当时它是java+oracle的组合。

    排序与此问题无关:)

    that MS page 例如。对于Unicode字段,排序规则仅用于定义列中的排序顺序, 指定数据的存储方式。

    如果您将数据存储为Unicode,则有一种独特的方式来表示它,这就是Unicode的目的:不需要定义与您要使用的所有语言兼容的字符集:)

    Unicode?“.例如:

    • 当我向服务器发送UTF-16字符串时,它是如何理解的?

    如果您的odbc客户端最终发送了消息,则会遇到麻烦 (编码字符串)发送到服务器,而不是发送 统一码 data:如果你这样做,服务器将使用预定义的编码(我的问题是:服务器将使用什么编码?因为它不是猜测,所以它必须是一个参数值),如果字符串使用了不同的编码, ,数据将被损坏。

    这与在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')
    

    因此,我的建议是:您需要确保pyodbc能够直接以Unicode格式发送数据。如果pyodbc未能做到这一点,您将得到意想不到的结果。

    我以客户端到服务器的方式描述了这个问题。但是,当从服务器向客户端进行通信时,也可能出现同样的问题。如果客户端无法理解Unicode数据,您可能会遇到麻烦。

    实际上,FreeTDS会为您处理事情,并将所有数据转换为UCS2 unicode。 ( Source ).

    • 服务器<-->FreeTDS:UCS2数据
    • /etc/freetds/freetds.conf )

    因此,如果您将UTF-8数据传递给pyodbc,我希望您的应用程序能够正常工作。事实上,正如 django-pyodbc ticket

    cramm0 FreeTDS 0.82并非完全没有bug,0.82与官方修补的0.82版本之间存在显著差异 here 。您可能应该尝试使用已修补的FreeTDS


    : 删除了与FreeTDS无关但仅与Easysoft商业odbc驱动程序相关的旧数据。对不起的。

        2
  •  2
  •   Paul Harrington    16 年前

    更正:我更改了.freetds.conf条目,以便客户端使用UTF-8

        tds version = 8.0
        client charset = UTF-8
        text size = 32768
    

    驱动程序在用于数据服务器端存储的UCS-2和提供给客户端/从客户端获取的UTF-8编码字符串之间进行透明转换。

    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 ?', )
    

        3
  •  1
  •   Roman Bataev    14 年前

    我在尝试绑定unicode参数时也遇到了同样的问题:

    我使用pyodbc 2.1.11。我必须申请 this 补丁使其与unicode一起工作,否则我偶尔会遇到内存崩溃错误。

        4
  •  0
  •   Eugene Yokota    16 年前

    pyodbc上有一个打开的bug Problem fetching NTEXT and NVARCHAR data .