2012-12-11 32 views
5

我無法從MSSQL服務器獲取有效的字符串到python。我相信某處存在編碼不匹配。我相信它在ODBC層和python之間,因爲我能夠在tsql和isql中獲得可讀的結果。如何配置pyodbc使用freeTDS和unixODBC正確接受來自SQL Server的字符串?

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執行相同的查詢成績單:

[email protected]:~# 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

[email protected]:~# 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
  • 蟒蛇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 
+0

在我對此的繼續工作中,我已經編譯了最新版本的pyodbc,3.0.7-beta06,但是沒有改變行爲。 – MatthewD

回答

2

所以在繼續工作之後,我現在將unicode字符轉換爲python。不幸的是,我偶然發現的解決方案與親吻你的表弟一樣令人滿意。

我解決了這個問題,安裝了python3和python3-dev軟件包,然後用python3重建了pyodbc。

現在我已經完成了這個工作,即使我仍然使用python 2.7運行它們,我的腳本現在仍然可以工作。

所以我不知道這樣做是什麼修復,但它現在可以工作,我可以繼續我開始的項目。

+1

這不是python版本,它是ubuntu的軟件包。 Debian也有同樣的問題。我刪除了debian的軟件包並通過'pip'安裝了pyodbc,一切正常,不需要python 3。 –

1

如果您遇到物料清單(字節順序標記)的問題,您有什麼可能?如果是這樣,也許這代碼片段將幫助:

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

+0

嗯。我已閱讀你的答案和鏈接,我不確定這是否是問題,或者至少我不知道如何處理。它確實出現在字符串u'\ U0072006f \ U006e0061 \ U00650067'中,每對字母被交換,但是沒有第7個字符,並且沒有我可以看到的BOM的符號。 – MatthewD

+0

我真的只是根據錯誤指出它不能「......編碼位置0-2中的字符,因爲它們不在範圍內」的問題。對不起,馬修。 –

0

如果您將pyodbc升級到版本3,問題將得到解決。

相關問題