2012-12-11 8 views
5

Nie mogę uzyskać prawidłowego ciągu z serwera MSSQL do Pythona. Uważam, że gdzieś jest niedopasowanie kodowania. Wierzę, że jest między warstwy ODBC i Pythona, ponieważ jestem w stanie uzyskać czytelne wyniki w tsql i isql.Jak skonfigurować pyodbc, aby poprawnie akceptować ciągi z SQL Server za pomocą freeTDS i unixODBC?

Jakie kodowanie znaków oczekuje pirodbc? Co muszę zmienić w łańcuchu, aby to zadziałało?

Przykład konkretny

Oto uproszczony python jak np

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

Wyjście tego scenariusza jest:

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

Alternatywnie, gdy ostatnia linia skrypt został zmieniony na:

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

Następnie wynik jest:

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) 

Zapis za pomocą TSQL do wykonania tego samego zapytania:

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

a także w 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 

Tak Pracowałem nad tym rano i wyglądał wysoko i nisko i nie zorientowali się, co jest nie tak.

Szczegóły

Oto szczegóły Wersja:

  • klient jest Ubuntu 12.04
  • freetds v0.91
  • unixodbc 2.2.14
  • python 2.7.3
  • pyodbc 2.1.7-1 (z pakietu ubuntu) & 3.0.7-beta06 (kompilowany ze źródeł)

  • Server XP z SQL Server Express 2008 R2

Oto zawartość kilku plików konfiguracyjnych na kliencie.

/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

W mojej dalszej pracy nad tym teraz skompilowałem najnowszą wersję pyodbc, 3.0.7-beta06, _but_ bez zmian w zachowaniu. – MatthewD

Odpowiedz

2

Więc po kontynuacji pracy otrzymuję teraz znaki Unicode w pythonie. Niestety rozwiązanie, na które natknąłem się, jest równie satysfakcjonujące jak całowanie kuzyna.

Rozwiązałem problem instalując pakiety python3 i python3-dev, a następnie odtwarzając pyodbc z python3.

Teraz, gdy to zrobiłem, moje skrypty działają teraz, mimo że nadal je uruchamiam z python 2.7.

Więc nie wiem, co zostało naprawione przez to, ale teraz działa i mogę przejść do projektu, od którego zacząłem.

+1

To nie jest wersja Pythona, to pakiet ubuntu. Debian miał ten sam problem. Usunąłem pakiet debiana i zainstalowałem pyodbc za pomocą 'pip' i wszystko działa dobrze, nie jest wymagany żaden python 3. –

1

Masz szansę na problem z zestawieniem komponentów (znacznikiem kolejności bajtów)? Jeśli tak, może to fragment kodu pomoże:

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

Znalazłem ten fragment na this page.

+0

Hmm. Przeczytałem twoją odpowiedź i link i nie jestem pewien, czy to jest problem, a przynajmniej nie wiem, jak coś z tym zrobić. Z ciągu "u" \ U0072006f \ U006e0061 \ U00650067 "wynika, że ​​każda para liter jest zamieniona, ale brakuje 7-ego znaku i żadnego znaku BOM, który widzę. – MatthewD

+0

Naprawdę po prostu zrobiłem ukłucie problemu na podstawie błędu mówiącego, że nie może "... zakodować znaków na pozycjach 0-2, ponieważ nie są one w zasięgu". Przepraszam Matthew. –

0

Po uaktualnieniu pyodbc do wersji 3 problem zostanie rozwiązany.

Powiązane problemy