2 votes

Problème d'unicode avec une requête PyODBC

J'ai des difficultés à interroger mon serveur MSSQL à l'aide de PyODBC.

Je pense que la raison en est que j'ai des colonnes qui sont nommées en utilisant l'unicode. Ces colonnes proviennent du pivotement d'une seule colonne de mes données principales.

La colonne en question est "afkastningsgrad_primær_drift".

Une idée de la façon dont je pourrais exécuter cette requête ? (construire une vue sur le serveur et renommer la colonne n'est pas une option en raison de mon manque de propriété du serveur).

SQL :

WITH dataTable AS (
    SELECT 
        KredsEjdNr, Navn, Vaerdi
    FROM qryEjendomsData

    WHERE 
        RegnskabsAar = 2016 
        AND Projekt = 1710
        AND Navn IN (
            'ekm_ko' , 'afkastningsgrad_primær_drift', 'fremst_pris_maelk'
        )
    GROUP BY KredsEjdNr, Navn, Vaerdi
), 
pivotData AS (

    SELECT * 
    FROM dataTable
    PIVOT
        (
            SUM(Vaerdi)
            FOR[Navn] IN (
                [ekm_ko], [afkastningsgrad_primær_drift], [fremst_pris_maelk]
            )
        )
    AS pivotTable
)

SELECT 
    CAST([KredsEjdNr] AS NVARCHAR) AS [kredsEjdNr], 
    CAST(ekm_ko AS int) AS [EKM pr ko],
    [afkastningsgrad_primær_drift] as [Afkastningsgrad],
    [fremst_pris_maelk] AS [Fremstillingspris pr. kg EKM]
 from pivotData
 where [ekm_ko] IS NOT NULL and [fremst_pris_maelk] IS NOT NULL
 order by kredsEjdNr

Code Python :

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
connectionstring = 'DRIVER={SQL Server Native Client 11.0};SERVER=server;DATABASE=database;UID=%s;PWD=%s' %(usr,pswd)
conn = pyodbc.connect(connectionstring)
cursor = conn.cursor()
dataList = cursor.execute(unicode(sql)).fetchall()

Erreur :

Traceback (dernier appel le plus récent) : Fichier "data.py", ligne 84, dans dataList = cursor.execute(unicode(sql)).fetchall() UnicodeDecodeError : le codec 'ascii' ne peut pas décoder l'octet 0xc3 en position 183 : ordinal n'est pas dans la plage(128)

2voto

Gord Thompson Points 30178

Le problème ne concerne pas les caractères Unicode dans les noms de colonnes, mais les caractères non ASCII. octets en str sous Python2. Lorsqu'un pyodbc .execute L'appel reçoit le texte de la commande comme un str il essaie de le traiter en utilisant l'encodage par défaut, qui est 'ascii' pour Python2.

Le code de test suivant

# -*- coding: utf-8 -*-
import sys
print("sys.getdefaultencoding() is '{0}'".format(sys.getdefaultencoding()))
import pyodbc

cnxn = pyodbc.connect("DSN=SQLmyDb", autocommit=True)
crsr = cnxn.cursor()

# setup test environment
crsr.execute(u"CREATE TABLE #tmp (afkastningsgrad_primær_drift INT)")
crsr.execute(u"INSERT INTO #tmp VALUES (1)")

print('')
print('Test_1: "SELECT * ..." as str')
sql = "SELECT * FROM #tmp"
print("  sql: " + repr(sql))
crsr.execute(sql)
print("    column name from result set: " + repr(crsr.description[0][0]))

print('')
print('Test_2: "SELECT colname ..." as str')
sql = "SELECT afkastningsgrad_primær_drift FROM #tmp"
print("  sql: " + repr(sql))
try:
    crsr.execute(sql)
    print("    OK")
except UnicodeDecodeError as ude:
    print("    UnicodeDecodeError: " + str(ude))

print('')
print('Test_3: "SELECT colname ..." as unicode')
sql = sql.decode('utf-8')
print("  sql: " + repr(sql))
try:
    crsr.execute(sql)
    print("    OK")
except Exception as ex:
    print("    Exception: " + str(ex))

cnxn.close()

produit

sys.getdefaultencoding() is 'ascii'

Test_1: "SELECT * ..." as str
  sql: 'SELECT * FROM #tmp'
    column name from result set: u'afkastningsgrad_prim\xe6r_drift'

Test_2: "SELECT colname ..." as str
  sql: 'SELECT afkastningsgrad_prim\xc3\xa6r_drift FROM #tmp'
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 27: ordinal not in range(128)

Test_3: "SELECT colname ..." as unicode
  sql: u'SELECT afkastningsgrad_prim\xe6r_drift FROM #tmp'
    OK

Le test_1 montre qu'un nom de colonne contenant des caractères Unicode est correctement renvoyé en tant qu'un unicode objet.

Le test_2 montre que l'encodage par défaut de Python2 ('ascii') s'étrangle sur un fichier str qui contient des octets UTF-8 supérieurs à 0x7F.

Le Test_3 montre qu'aucune erreur ne se produit si nous utilisons .decode pour convertir le str (contenant des octets UTF-8) dans un fichier de type unicode que nous passons ensuite à l'objet .execute méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X