2012-12-11 12 views
5

Ich kann keine gültige Zeichenfolge von einem MSSQL-Server in Python abrufen. Ich glaube, irgendwo gibt es ein Kodierungs-Missverhältnis. Ich glaube, es ist zwischen der ODBC-Schicht und Python, weil ich lesbare Ergebnisse in Tsql und Isql erhalten kann.Wie konfiguriere ich pyodbc, um Zeichenfolgen von SQL Server mit freeTDS und unixODBC korrekt zu akzeptieren?

Welche Zeichencodierung erwartet pyodbc? Was muss ich in der Kette ändern, damit dies funktioniert?

Spezifisches Beispiel

Hier ist ein vereinfachtes Python-Skript als Beispiel:

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

Die Ausgabe dieses Skripts ist:

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

Alternativ kann, wenn die letzte Zeile Das Skript wird geändert in:

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

Dann ist das Ergebnis:

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) 

Ein Transkript mit Tsql die gleiche Abfrage auszuführen:

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

und auch in 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 

So Ich habe am Morgen daran gearbeitet und sah hoch und niedrig und habe nicht herausgefunden, was nicht stimmt.

Einzelheiten

sind hier Version Details:

  • Client ist Ubuntu 12.04
  • freetds v0.91
  • unixodbc 2.2.14
  • Python 2.7.3
  • pyodbc 2.1.7-1 (aus dem Paket ubuntu) & 3.0.7-beta06 (aus den Quellen kompiliert)

  • Server ist XP mit SQL Server Express 2008 R2

Hier werden die Inhalte von wenigen Konfigurationsdateien auf dem Client sind.

/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

In meiner fortlaufenden Arbeit habe ich jetzt die neueste Version von pyodbc, 3.0.7-beta06, _but_ keine Änderung im Verhalten zusammengestellt. – MatthewD

Antwort

2

Also nach der fortlaufenden Arbeit bekomme ich jetzt Unicode-Zeichen in Python. Leider ist die Lösung, über die ich gestolpert bin, ungefähr so ​​befriedigend wie das Küssen deines Cousins.

Ich löste das Problem, indem ich die Pakete python3 und python3-dev installierte und dann pyodbc mit python3 neu erstellte.

Jetzt, da ich das getan habe, funktionieren meine Skripte jetzt, obwohl ich sie immer noch mit Python 2.7 ausführe.

Also ich weiß nicht, was behoben wurde, aber es funktioniert jetzt und ich kann zu dem Projekt weitergehen, mit dem ich angefangen habe.

+1

Es ist nicht die Python-Version, es ist Ubuntu-Paket. Debian hatte das gleiche Problem. Ich habe debian's Paket entfernt und pyodbc über 'pip' installiert und alles funktioniert gut, kein Python 3 ist erforderlich. –

1

Haben Sie ein Problem mit einer Stückliste (Byte Order Marker)? Wenn ja, wird vielleicht dieser Code-Snippet helfen:

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

ich auf this page dass Schnipsel gefunden.

+0

Hmm. Ich habe deine Antwort und den Link gelesen und bin mir nicht sicher, ob das das Problem ist oder zumindest weiß ich nicht, wie ich damit etwas anfangen soll. Es erscheint aus der Zeichenkette u '\ U0072006f \ U006e0061 \ U00650067', dass jedes Buchstabenpaar getauscht wird, aber ein fehlendes 7. Zeichen und kein Zeichen einer Stückliste, die ich sehen kann, fehlen. – MatthewD

+0

Ich war wirklich nur ein Stich auf das Problem basierend auf den Fehler, dass es nicht konnte "... codieren die Zeichen in den Positionen 0-2, weil sie nicht in Reichweite sind". Tut mir leid Matthew –

0

Wenn Sie das Pyodbc auf Version 3 aktualisieren, wird das Problem gelöst.