Umlaute und MySQL Datenbankabfragen über Python

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Booyeoo
User
Beiträge: 5
Registriert: Samstag 10. Januar 2009, 22:26

Hallo Zusammen,

Wers kürzer mag, runterscrollen zur Frage :-) --->

Ich bin ein bisher begeisterter Python Programmierer und
bisher war alles recht simpel und einfach mithilfe von Google zu lösen.
Nun bin ich an einem Punkt der Verzeiflung, da mir dieses Wirr-War um das encode decode utf-8 latin-1 repr-Zeug zuviel wurde und ich alle Kombinationen aus diesen ausprobiert habe. Nun hoffe ich hier Hilfe zu finden.

Ich habe eine Verbindung zu meiner DB, welcher blendend funktioniert. Kann dort Datensätze auslesen und diese auch vernünftig mittels .decode("utf-8") in meiner GUI anzeigen lassen.

Frage:
Nun habe ich aber das Problem, dass wenn ich eine SQL Abfrage zum Server schicke, er die Umlaute nicht schluckt, wenn ich gerade eine Stadt mit Umlaut gewählt hab:

Code: Alles auswählen

(...)def OnCompute(self,event):
        # Fill Pegel Values 1
        selected = self.PegelAuswahl1.GetStringSelection()
        if selected <> None:
            cur2=get_cursor(con(1))  # Meine Connection , Aufbau   
            sql2="Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"" + selected +"\" LIMIT " + str(LIMIT)
            cur2.execute(sql2)
            l4=cur2.fetchall()
            dis(cur2,1) # Meine Connection Abbau
(...)
Wenn nun selected ein String ist mit äüö, dann gibts die folgende Fehlermeldung:

z.B. für Düsseldorf

Code: Alles auswählen

Warning (from warnings module):
  File "C:\Python25\paddelboot.py", line 172
    cur2.execute(sql2)
Warning: Incorrect string value: '\xFCsseld...' for column 'Pegel' at row 1
Was muss ich mit selected machen damit er es verwenden kann??

Habe schon

Code: Alles auswählen

repr(selected) # Passiert komischerwise garnix
selected.encode("utf-8") # Fehlermeldung
selected.encode("latin-1") # Fehlermeldung
Nutze Windows Python 2.5
Server ist auf Linux mit MySQL 14.12 Dist 5.0.32


Danke für jede Antwort
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Zunächst ein paar Anmerkungen:

- Dein Query-String solltest Du nicht per "+" zusammenbauen (SQL-Injection Gefahr!).

- Deine Variablen solltest Du besser benennen. "l4" und "cur2" ist wenig aussagekräftig.

Zum Problem:

Welches Encoding verwendet denn die DB? utf-8? Musst Du die Query evtl. als Unicode-Objekt abliefern? Dann solltest Du es so lösen:

Code: Alles auswählen

parameter = u"äöü"
cur2.execute(u"select xyz from Table where id=%s", (parameter,))
Wobei parameter eben auch ein Unicode-String sein muss!

Folgende Links könnten interessant sein:
http://www.python-forum.de/viewtopic.php?=&p=50426
http://www.python-forum.de/topic-8002.html
Booyeoo
User
Beiträge: 5
Registriert: Samstag 10. Januar 2009, 22:26

:(


Hallo, habe meinen Code entsprechend der Vorgaben umgeschrieben, jedoch passiert bei der Anfrage anscheinend nix mehr. Ich bekomme keine Werte mehr zurück für Städte ohne Umlaute und bei Städten mit Umlauten habe ich immernoch den gleichen Fehler.

Die DB ist utf-8:

Code: Alles auswählen

Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8


Neuer Code: (auskommentierter Vorschlag)

Code: Alles auswählen

conDB=get_cursor(con(1))      
            #conDB.execute(u"select xyz from Table where id=%s", (parameter,)) 
            conDB.execute(u"Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"%s\" LIMIT 5", (selected,))
            listValues=conDB.fetchall()
            dis(conDB,1)
Fehlermeldung:

Code: Alles auswählen

Warning (from warnings module):
  File "C:/Python25/Copy of paddelboot.py", line 172
    conDB.execute(u"Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"%s\" LIMIT 5", (selected,))
Warning: Incorrect string value: '\xFCsseld...' for column 'Pegel' at row 1
Habe in der Shell auch ein wenig rumgespielt, denn ich verstehe diese Anweisung mit %s nicht so ganz.
Ich müsste doch den String in Utf8 also Unicode verwandeln oder?
Also eigentlich das machen:

Code: Alles auswählen

selected.encode("utf-8")
aber dann gibts den Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "<pyshell#27>", line 1, in <module>
    selected.encode("utf-8")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xfc in position 1: ordinal not in range(128)
Das mit dem u vor dem String ist eher schlecht,
da ich den String ja vorher nicht im Code kenne und dieser vom User ausgewählt wird. Ich müsste also die Variable selected irgendwie umwandeln, dies geht anscheinend mit .encode("latin-1"). Aber dies liefert mir im Endeffekt dann leider auch nicht das gewünschte Ergebnis.

Code: Alles auswählen

>>> selected="Düsseldorf"
>>> selected
'D\xfcsseldorf'
>>> selected.encode("latin-1")
u'D\xfcsseldorf'
>>> u"Düsseldorf"
u'D\xfcsseldorf'
Der Code von oben mit latin-1 encode:
Hier funktionieren auch die normalen Werte ohne Umlaut...

Code: Alles auswählen

conDB=get_cursor(con(1))           
            sql2="Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"" + selected.encode("latin-1") +"\" LIMIT "+ str(LIMIT)
            conDB.execute(sql2)
            listValues=conDB.fetchall()
            dis(conDB,1)
Aber sobald eine Stadt mit Umlaut ausgewählt wird gibts:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Python25/Copy of paddelboot.py", line 190, in OnCompute
    sql2="Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"" + selected.encode("latin-1") +"\" LIMIT "+ str(LIMIT)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xfc in position 1: ordinal not in range(128)

Muss ich jetzt noch irgendwelche SqlAlchemy oder PyLucid Pakete installieren damit das läuft?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du hast das Unicode-Konzept noch nicht verstanden (wa sich nicht schlimm finde, da ich das am Anfang selber nicht ganz kapiert hatte ... und immer noch manchmal darüber stolpere ;-) )

Das hier dürfte helfen:
[wiki]Von Umlauten, Unicode und Encodings[/wiki]?highlight=(unicode)

[wiki]User Group München[/wiki]?action=AttachFile&do=get&target=unicode-folien.pdf

Arbeite das mal durch, dann kapierst Du das auch :-)

Außerdem musst Du mal beim MySQLdb-Modul gucken, ob Deine Version Unicode erwartet oder eben nicht. Davon hängt ja ab, wie Du die Strings senden musst.
Booyeoo
User
Beiträge: 5
Registriert: Samstag 10. Januar 2009, 22:26

:D Juhuu!

Danke, schade dass man nicht immer die richtigen Seiten googelt ;-)

Ich musste erst das verstehen:

iso-8859-1 --> Unicodestring --> utf-8
utf-8 --> Unicodestring --> iso-8859-1

danach lief es!!!!!

Laufender Code:

Code: Alles auswählen

s_uni=selected.decode("latin-1") #geht auch mit iso-8859-1
#print s_uni
s_utf=s_uni.encode("utf-8")
#print s_utf
sql2="Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"" + s_utf +"\" LIMIT "+ str(LIMIT)
Leider klappt es nicht mit:(Gefahr von SQL-Injection besteht, aber so wie ich das mit SQL Injection verstanden habe, tritt das nur auf, wenn man hinter der Anweisung noch eine Anweisung einbaut)

Code: Alles auswählen

s_uni=selected.decode("latin-1")
s_utf=s_uni.encode("utf-8")
#conDB.execute(u"select xyz from Table where id=%s", (parameter,))
sql="Select Datum,Uhrzeit,Stand From PegelstaendeBereinigt Where Pegel=\"%s\" LIMIT %s"
conDB.execute(sql, (s_utf,LIMIT))
Kriege hierbei eine leere Fehlermeldung...(Ein weißes Fenster spring aus meiner GUI mit dem Title wxPython:stdout/stderr) :?
BlackJack

Die Anführungszeichen im SQL dürften zuviel sein. Um's korrekte "quoten" kümmert sich das Datenbankmodul, wenn man die Werte bei `execute()` als zweites Argument angibt.
Antworten