Seite 1 von 2

MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 10:16
von taake
Moin,
ausgehend von diesem thread http://www.python-forum.de/viewtopic.php?f=23&t=32257
Den ich an dieser Stelle bezüglich anderem topic und inhalt nicht weiter nutzen möchte.

Also ich hab das sqlalchemy an dieser stelle erstmal verworfen, werde ich an anderer stelle ansetzen, aber dieses linux <-> win odbc geschiss ist mir fürs erste genug action.

Vom SQL Query läuft es jetzt

Code: Alles auswählen

#!/usr/bin/python2.7

import pyodbc

driver = '/usr/lib64/libtdsodbc.so'
cnxn = pyodbc.connect(
                        DRIVER = driver,
                        SERVER = '<ip>',
                        DATABASE = '<database>',
                        TDS_Version = '8.0',
                        PORT = '1433',
                        UID = '<user>',
                        PWD = '<pass>')
cursor = cnxn.cursor()
cursor.execute("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS")
row = cursor.fetchone()
#print type(row)
if row:
    print row
Leider hat die 'Freude' über eine stabile Verbindung nur kurz gehalten.
Die Rückgabe ist leider nicht ganz das was ich mir erhofft hatte.

Code: Alles auswählen

(u't\x00i\x00m\x00e\x00s\x00t\x00a\x00m\x00p\x00', )
Kann mir Jemand auf die Sprünge helfen, wie es weitergehen soll?
Ich müsste jetzt erstmal identifizieren was ich da eigentlich bekomme und es dann als utf8 umwandeln, oder?
Ein einfaches
print str(row).decode(encoding='UTF-8')
bringt leider keine abhilfe ...

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 10:57
von Leonidas
Wenn du schaust, dann steht da "timestamp", nur das zwischen allen Buchstaben Null-Bytes (``\x00``) sind, da hilft dir UTF-8 auch nicht.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 11:12
von taake
:shock: jetzt wo du es sagst ...
Stimmt das steht da drin.

Okay, dann ändere ich die Frage etwas ab, gibt es eine bessere methode als alle '\x00' aus der Rückgabe-liste rauszuschneiden?

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 11:22
von Leonidas
Stehen die Null-Bytes so in der Datenbank drin?

Code: Alles auswählen

r = (u't\x00i\x00m\x00e\x00s\x00t\x00a\x00m\x00p\x00', )
[e.replace('\x00', '') for e in r]

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 11:38
von EyDu
Was sagt den die Spalte CHARACTER_SET_NAME? Da sollte doch die Codierung drin stehen.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 11:40
von BlackJack
Kann es sein dass das UTF-16 ist? Denn dann sollte man das dekodieren und nicht einfach die Nullbytes wegwerfen. Und da der Rückgabewert von der Datenbank schon Unicode ist defkodiert die Datenbank beziehungsweise das Modul das schon, nur halt nicht mit der richtigen Kodierung. Statt also selbst zu kodieren und dann wieder zu dekodieren sollte man rausfinden wie man der Datenbank sagt, dass man UTF16 verwenden will beziehungsweise dass die Daten so in der DB vorliegen.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 11:51
von Leonidas
Oh, das sieht in der Tat sehr nach UTF-16 ohne BOM aus.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 13:38
von taake
Also ich hab gerade mal gefragt, und die Antwort erhalten "kA"
also kann ich nicht sagen ob das in der Datenbank auch durch nullbyte getrennt ist.

Hab hier nur via VM den 'MS SQL Server Management Studio' zur Verfügung und der gibt sich eher in MS marnie ziemlich zurückhaltend, was informationen betrifft.

Ebenfalls funktioniert ein

Code: Alles auswählen

select * from CHARACTER_SET_NAME 
nicht wie gewünscht

Ungültiger Objektname 'CHARACTER_SET_NAME'.

Allerdings ist das in dem Fall glaube ich zum Glück nicht von relevanz, da ich nur anfragen an die db stellen möchte und die rückgabe in meine eigene mysql db schreiben will.

Allerdings ist es natürlich dennoch grundsätzlich von interesse zu wissen wie ich das charset rausbekomme bzw. es ggf. direkt ohne replace so bekomme wie ich möchte.


desweiteren hät ich noch ne n00b frage und zwar wo ist der unterschied zwischen:

Code: Alles auswählen

r = (u't\x00i\x00m\x00e\x00s\x00t\x00a\x00m\x00p\x00', )
print [e.replace('\x00', '') for e in r]
&

Code: Alles auswählen

r = (u't\x00i\x00m\x00e\x00s\x00t\x00a\x00m\x00p\x00', )
for e in r:
    print e.replace('\x00', '')
Für mich als laien gibt es da keinen signifikaten unterschied und dennoch ist die rückgabe anders
beim ersten [u'timestamp'] und beim zweiten einfach nur timestamp
das die [] beim ersten von der zusammenfassung stammen versteh ich ja noch aber warum ist dort noch das u' ?

Bzw. was ich noch weniger verstehe, ist mir gerade durch ein copy&paste fehler aufgefallen:

Code: Alles auswählen

r = (u't\x00i\x00m\x00e\x00s\x00t\x00a\x00m\x00p\x00', )
for e in r:
    print e
geht auch und gibt timestamp zurück

An der Stelle schon mal ein danke, ihr habt mir weitergeholfen.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 13:49
von BlackJack
@taake: Das SELECT kann ja nicht gehen solange es keine Tabelle mit dem Namen `CHARACTER_SET_NAME` gibt. Und natürlich ist diese Einstellung relevant, denn Du möchtest ja die Zeichenketten so haben wie sie sein sollten und nicht irgendwie falsch kodiert. Also nicht so wie jetzt.

Vergiss bitte `replace()` als Lösungsansatz sofort wieder. Wenn das UTF-16 ist, und das ist *sehr* wahrscheinlich, dann funktioniert das nur solange nur ASCII-Zeichen vorkommen können. Und darauf sollte man sich nicht verlassen, insbesondere dann nicht, wenn man das auch ordentlich lösen kann, ohne das solche ”Reparaturen” an den Rückgabewerten nötig sind.

Eine „list comprehension” erstellt eine Liste — denn genau *dafür* gibt es dieses Konstrukt. Und eine ``for``-Schleife erstellt gar nichts sondern ermöglicht es Code wiederholt mit verschiedenen Werten auszuführen.

Dein letztes Beispiel „geht” weil offensichtlich das Programm welches die Ausgabe darstellt Nullbytes einfach ignoriert. Die sind trotzdem da und man möchte sie dort sicher nicht haben.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 13:51
von Leonidas
Der Punkt ist ja, dass es nicht reicht wenn du einfach die Nulls rausfischt, weil wenn da irgendein exotisches Zeichen wie etwa das €-Zeichen drinsteht, dann fliegt dir das um die Ohren. Ebenfalls wenn du da Daten im inkorrekten Encoding reinschreibst können andere Tools damit nicht unbedingt umgehen.

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 13:59
von /me
taake hat geschrieben:Für mich als laien gibt es da keinen signifikaten unterschied und dennoch ist die rückgabe anders
beim ersten [u'timestamp'] und beim zweiten einfach nur timestamp
das die [] beim ersten von der zusammenfassung stammen versteh ich ja noch aber warum ist dort noch das u' ?
Du gibst dort völlig unterschiedliche Dinge aus. Im ersten Fall ist es eine Liste und deren Werte werden in ihrer Repräsentation ausgegeben. Im zweiten Fall gibst du einzelne Zeichen aus.

Code: Alles auswählen

>>> data = [u'text']
>>> print data
[u'text']
>>> print data[0]
text
>>> print repr(data[0])
u'text'

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 14:50
von EyDu
taake hat geschrieben:Ebenfalls funktioniert ein

Code: Alles auswählen

select * from CHARACTER_SET_NAME 
nicht wie gewünscht

Ungültiger Objektname 'CHARACTER_SET_NAME'.
Du solltest halt nicht einfach Code raten, sondern in die Dokumentation schauen ;-)

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 15:54
von Leonidas
EyDu hat geschrieben:Du solltest halt nicht einfach Code raten, sondern in die Dokumentation schauen ;-)
Ob die MySQL-Doku so relevant ist für MS SQL?

Re: MS SQL pyodbc encoding problem

Verfasst: Dienstag 17. September 2013, 15:54
von taake
Bringt mir die Doku von mysql auch bei mssql was?

Kann ich das irgendwie verifizieren dass das utf-16 ist? ( bei mssql )

Und wenn ja und es uft-16 ist, wie soll ich dann vorgehen?

edit:
Ich hab gerade noch was gefunden, vielleicht hilft das

Code: Alles auswählen

select data_type, character_set_catalog, character_set_schema, character_set_name, collation_catalog, collation_schema, collation_name, count(*) count
from information_schema.columns
group by data_type, character_set_catalog, character_set_schema, character_set_name, collation_catalog, collation_schema, collation_name;
Bild

Re: MS SQL pyodbc encoding problem

Verfasst: Mittwoch 18. September 2013, 00:12
von EyDu
taake hat geschrieben:Bringt mir die Doku von mysql auch bei mssql was?
Ähem, natürlich ... also, irgendwie, ... hmm, nicht so richtig :oops:

Code: Alles auswählen

>>> difflib.SequenceMatcher(None, "MySQL", "MS SQL").ratio()
0.7272727272727273

Re: MS SQL pyodbc encoding problem

Verfasst: Mittwoch 18. September 2013, 16:49
von Sirius3
@taake: Jedes Datenbanksystem hat sein Default-Encoding (bei MS-Sql wahrschienlich UC16) das aber normalerweise noch für jede Tabellenspalte konfigurierbar ist. Wenn Du also keine bestimmtest Encoding anforderst, wirst Du auch irgendetwas bekommen, mit dem Du nichts anfangen kannst. Denn jede Annahme die Du über das Encoding machst, kann im nächsten Moment wieder falsch sein, und Du bekommst Fehler, die zur unpassensten Zeit auftreten.

Deshalb immer bei jeder Verbindung ein Encoding vorgeben (angeblich »cnxn = pyodbc.connect(…, CHARSET='UTF8')«), jede andere Lösung führt nur ins Chaos.

Re: MS SQL pyodbc encoding problem

Verfasst: Donnerstag 19. September 2013, 08:06
von Hyperion
Sirius3 hat geschrieben:...(bei MS-Sql wahrschienlich UC16)
Wo denkst Du hin? Bei MS gibt es nur ANSI und UNICODE :twisted:

(Und Du meintest UCS-2 bzw. UTF-16?)

(Aber vielleicht bin ich auch zu gemein zu den Machern der SQL Server Docs - für MFC und auch .NET habe ich schon so oft solchen Wischi-Waschi-Müll gefunden... )

Re: MS SQL pyodbc encoding problem

Verfasst: Donnerstag 19. September 2013, 08:39
von /me
Hyperion hat geschrieben:Wo denkst Du hin? Bei MS gibt es nur ANSI und UNICODE :twisted:
Jetzt nicht wirklich, oder? Unicode ist keine Kodierung, Unicode ist ein Konzept.

Re: MS SQL pyodbc encoding problem

Verfasst: Donnerstag 19. September 2013, 08:43
von BlackJack
@/me: ANSI ist auch keine Kodierung, sondern eine Institution. Wenigstens sind sie konsistent. :-)

Re: MS SQL pyodbc encoding problem

Verfasst: Donnerstag 19. September 2013, 08:48
von taake
Moin zusammen,

komme gerade endlich dazu daran weiter zu arbeiten.
Allerdings gibt es ein merkwürdiges Phänomen, seit dem ich mir die vorerst endgültige Abfrage zusammen gebastelt habe bekomme ich die auch als vernünftigen Output. Sprich keine Nullbytes mehr zwischen den einzelnen Buchstaben.
Warum dies so ist kann ich allerdings nicht sagen.
Habe nachträglich zur Sicherheit allerdings das CHARSET='UTF8' in den connection string intigriert.

Also vielen Dank an dieser Stelle an alle Unterstützer, von hier aus sollte ich erstmal alleine weiterkommen.

Wieso gibts hier eigentlich kein Bier smilie ? :D