2012-12-11 27 views
5

Tôi không thể nhận được một chuỗi hợp lệ từ một máy chủ MSSQL vào python. Tôi tin rằng có một mã hóa không khớp ở đâu đó. Tôi tin rằng nó là giữa các lớp ODBC và python bởi vì tôi có thể nhận được kết quả có thể đọc được trong tsql và isql.Làm thế nào để cấu hình pyodbc để chấp nhận đúng chuỗi từ SQL Server bằng cách sử dụng freeTDS và unixODBC?

Mã hóa ký tự nào mà pyodbc mong đợi? Tôi cần phải thay đổi gì trong chuỗi để làm việc này?

cụ thể Ví dụ

Dưới đây là một kịch bản python đơn giản như một ví dụ:

#!/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 

Kết quả của kịch bản này là:

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

Ngoài ra, nếu dòng cuối cùng của tập lệnh được đổi thành:

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

Sau đó, kết quả là:

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) 

Một bảng điểm sử dụng TSQL để thực hiện cùng một truy vấn:

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

và cũng trong 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 

Vì vậy, Tôi đã làm việc này vào buổi sáng và nhìn cao và thấp và đã không tìm ra những gì là không ổn.

Chi tiết

Dưới đây là chi tiết phiên bản:

  • Khách hàng là Ubuntu 12.04
  • freetds v0.91
  • unixodbc 2.2.14
  • python 2.7.3
  • pyodbc 2.1.7-1 (từ gói ubuntu) & 3.0.7-beta06 (biên soạn từ nguồn)

  • Server là XP với SQL Server Express 2008 R2

Dưới đây là nội dung của một vài tập tin cấu hình trên máy khách.

/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

Trong công việc tiếp tục của tôi về điều này, tôi đã biên soạn phiên bản mới nhất của pyodbc, 3.0.7-beta06, _but_ không thay đổi hành vi. – MatthewD

Trả lời

2

Vì vậy, sau khi tiếp tục công việc, bây giờ tôi nhận được các ký tự unicode thành python. Thật không may là giải pháp tôi đã vấp phải là về thỏa mãn như hôn người em họ của bạn.

Tôi giải quyết vấn đề bằng cách cài đặt các gói python3 và python3-dev và sau đó xây dựng lại pyodbc bằng python3.

Bây giờ tôi đã thực hiện việc này, các tập lệnh của tôi giờ hoạt động ngay cả khi tôi vẫn chạy chúng với python 2.7.

Vì vậy, tôi không biết điều gì đã được khắc phục bằng cách thực hiện việc này, nhưng bây giờ nó hoạt động và tôi có thể chuyển sang dự án mà tôi đã bắt đầu.

+1

Đây không phải là phiên bản python, đó là gói của ubuntu. Debian có cùng một vấn đề. Tôi gỡ bỏ gói debian và cài đặt pyodbc thông qua 'pip' và mọi thứ hoạt động tốt, không yêu cầu python 3. –

1

Bất kỳ cơ hội nào bạn gặp sự cố với BOM (Đánh dấu đơn hàng)? Nếu vậy, có thể đoạn mã này sẽ giú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")) 

Tôi tìm thấy đoạn mã đó trên this page.

+0

Hmm. Tôi đã đọc câu trả lời của bạn và liên kết và tôi không chắc chắn đây là vấn đề hay ít nhất tôi không biết làm thế nào để làm điều gì đó với nó. Nó xuất hiện từ chuỗi u '\ U0072006f \ U006e0061 \ U00650067' rằng mỗi cặp chữ cái được hoán đổi nhưng có một ký tự 7 bị thiếu và không có dấu hiệu nào của BOM mà tôi có thể thấy. – MatthewD

+0

Tôi đã thực sự chỉ lấy một đâm vào vấn đề dựa trên lỗi nói rằng nó không thể "... mã hóa các ký tự ở các vị trí 0-2 vì chúng không nằm trong phạm vi". Xin lỗi Matthew. –

0

Nếu bạn nâng cấp pyodbc lên phiên bản 3, sự cố sẽ được giải quyết.