Kleines Datenbankbeispiel (Access per pyODBC)

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Dienstag 20. November 2007, 17:49

Hallo!

Es tauchen immer wieder Fragen auf, die ich mit diesem Beispiel beantworten möchte:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import pyodbc

DBENCODING = "cp1252"
DSN = (
    "DRIVER={Microsoft Access Driver (*.mdb)};"
    "DBQ=J:\\DOKUMENTE UND EINSTELLUNGEN\\GEROLD\\DESKTOP\\test.mdb"
)


def create_table(conn):
    
    cur = conn.cursor()
    sql = """
    CREATE TABLE addresses (
      id AUTOINCREMENT PRIMARY KEY,
      first_name VARCHAR(50),
      last_name VARCHAR(50)
    )
    """
    cur.execute(sql)
    conn.commit()


def insert_address(conn, first_name, last_name):
    
    # Von Unicode nach DBENCODING umwandeln
    if isinstance(first_name, unicode):
        first_name = first_name.encode(DBENCODING)
    if isinstance(last_name, unicode):
        last_name = last_name.encode(DBENCODING)
    
    cur = conn.cursor()
    sql = """
    INSERT INTO addresses (
      first_name, last_name
    ) VALUES (
      ?, ?
    )
    """
    cur.execute(sql, (first_name, last_name))
    conn.commit()


def get_all_addresses(conn):
    
    cur = conn.cursor()
    sql = """
    SELECT
      first_name, last_name
    FROM
      addresses
    ORDER BY
      first_name, last_name
    """
    cur.execute(sql)
    
    #Jede Zeile durchlaufen und die Textfelder nach Unicode umwandeln
    for row in cur:
        row[0] = row[0].decode(DBENCODING)
        row[1] = row[1].decode(DBENCODING)
        yield row


def main():
    
    conn = pyodbc.connect(DSN)

    create_table(conn)
    
    insert_address(conn, u"Gerold", u"Penz")
    insert_address(conn, u"Über", u"den Wolken")
    
    for row in get_all_addresses(conn):
        print repr(row)
        first_name = row[0]
        last_name = row[1]
        print repr(first_name), repr(last_name)
    
    conn.close()

if __name__ == "__main__":
    main()
Vielleicht kommentiere ich es später noch ein wenig mehr. Aber jetzt habe ich keine Zeit mehr dafür.


EDIT: ACHTUNG! Das Verhalten von pyODBC bei Umlauten hat sich anscheinend geändert. Siehe Beitrag http://www.python-forum.de/post-124912.html#124912


lg
Gerold
:-)
Zuletzt geändert von gerold am Dienstag 3. Februar 2009, 09:31, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Dienstag 20. November 2007, 18:27

Ich wage es ja nicht zu hoffen, aber geht das auch unter Linux? :?
Andy
User
Beiträge: 196
Registriert: Sonntag 1. Januar 2006, 20:12
Wohnort: aus dem hohen Norden....

Dienstag 20. November 2007, 19:02

Jan-Peer hat geschrieben:Ich wage es ja nicht zu hoffen, aber geht das auch unter Linux? :?
Also da könnte man sich auch fast fragen, warum Halvar äh Gerold die Shebang angegeben hat. :wink: ...Ich habe gar kein Linux!
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 20. November 2007, 19:35

Jan-Peer hat geschrieben:Ich wage es ja nicht zu hoffen, aber geht das auch unter Linux? :?
Theoretisch schon, wenn du den passenden ODBC-Treiber installiert hast. Die frage ist nur: wo bekommt man unter Linux einen ODBC-Treiber für Access-Datenbanken her.

pyODBC soll aber schlecht unter Unices laufen, mxODBC läuft hingegen wohl besser. Gibt es auch schon seit Jahren für Unices.
Andy hat geschrieben:Also da könnte man sich auch fast fragen, warum Halvar äh Gerold die Shebang angegeben hat. :wink: ...Ich habe gar kein Linux!
Unter Windows brauchst du die Shebang nur manchmal, unter bestimmten Servern wie dem Apache für CGI-Skripte. Ansonsten werden sie ignoriert. Unter Linux kannst du hingegen das Executable-Bit setzen und schon kannst du es laufen lassen. Ich füge auch unter Windows Shebang-Zeilen in meine Skripte hinzu, warum auch nicht?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Andy
User
Beiträge: 196
Registriert: Sonntag 1. Januar 2006, 20:12
Wohnort: aus dem hohen Norden....

Dienstag 20. November 2007, 19:44

Leonidas hat geschrieben:Unter Windows brauchst du die Shebang nur manchmal, unter bestimmten Servern wie dem Apache für CGI-Skripte. Ansonsten werden sie ignoriert. Unter Linux kannst du hingegen das Executable-Bit setzen und schon kannst du es laufen lassen. Ich füge auch unter Windows Shebang-Zeilen in meine Skripte hinzu, warum auch nicht?
Oh, dass das unter Windows greifen kann, wusste ich nicht. Danke Leo.
Gruß Andy
Aquerias
User
Beiträge: 28
Registriert: Freitag 28. September 2007, 10:33

Mittwoch 21. November 2007, 15:07

Hallo Gerold,

ich bin gerade dabei Dein Beispiel zu testen. Ich verstehe aber nicht ganz warum die Strings von Unicode nach DBENCODING umgewandelt wird?

Was mache ich wenn ich statt einem String eine Zahl habe? Wie weit muss ich den Python-Code ändern?

Gruß

Aquerias
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 21. November 2007, 15:32

Aquerias hat geschrieben:ich bin gerade dabei Dein Beispiel zu testen. Ich verstehe aber nicht ganz warum die Strings von Unicode nach DBENCODING umgewandelt wird?
Das liegt daran, dass du kein Unicode ausgeben kannst. Nochmal: du kannst kein Unicode außerhalb deines Programmes nutzen. Unicode existiert nur im Speicher des Python-Prozesses. Daher musst du Strings die du nach "außen" schickst, zu Bytestrings machen. Damit das mit den Umlauten klappt musst du natürlich das richtige Encoding verwenden, also dass der Datenbank, daher `DBENCODING`.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Aquerias
User
Beiträge: 28
Registriert: Freitag 28. September 2007, 10:33

Mittwoch 21. November 2007, 15:53

Danke für die schnelle Antwort,

erscheint mir logisch. Aber was mach ich mit meinen Zahlenwerten?
Muss ich die auch umwandeln?

Sorry, aber ist für mich absolutes Neuland.

MfG.

Aquerias
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 21. November 2007, 16:07

Jan-Peer hat geschrieben:Ich wage es ja nicht zu hoffen, aber geht das auch unter Linux? :?
Hallo Jan-Peer!

Als ich diese Frage gelesen hatte, wollte ich es wissen. Ich versuchte in Virtual Box, mit "Ubuntu 7.4" (glaube ich) pyodbc zum Laufen zu bekommen.

>> aptitude install unixodbc unixodbc-dev
>> aptitude install buildessential
>> aptitude install libmdbodbc

Dann holte ich mir den Quellcode von pyodbc.

Ein ``python setup.PY install`` schlug fehl. Dann korrigierte ich setup.PY ein wenig, aber trotzdem konnte ich das Ding aber immer noch nicht kompilieren.

Dann probierte ich noch *ceODBC* aus. Das konnte ich kompilieren und installieren. Aber ich schaffte es nicht, einen geeigneten DSN-String für die Testdatenbank herauszufinden. Es wurde immer ein ungültiger Treiber oder irgendetwas von "illegal Source..." (oder so) gemeldet.

Dann gab ich es auf. Unter Linux auf eine MDB zuzugreifen ist mir einfach zu kompliziert. Ich weiß nicht was ich übersehen habe und ich werde mich auch nicht mehr darum kümmern das herauszufinden. :evil:

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 21. November 2007, 16:13

Ich habe schon geschrieben, das pyodbc unter Linux schlecht läuft und mxODBC besser ist...

Das Problem unter Linux ist nicht ODBC selbst, sondern dass es schlichtweg keinen ODBC-Treiber für Access gibt. Unter Windows gibt es den Treiber vermutlich auch nur, wenn Access ihn selbst bereitstellt.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 21. November 2007, 16:30

Aquerias hat geschrieben:Ich verstehe aber nicht ganz warum die Strings von Unicode nach DBENCODING umgewandelt wird?

Was mache ich wenn ich statt einem String eine Zahl habe? Wie weit muss ich den Python-Code ändern?
Hallo Aquerias!

Ich möchte Leonidas Ausführungen noch ergänzen. Aber vorher: "Zahlen sind kein Text und müssen nicht in irgendein Encoding umgewandelt und auch nicht von irgendeinem Encoding zurückgewandelt werden. Das betrifft nur Text."

Und jetzt zur Erklärung:

Access läuft unter Windows und speichert alles was man ihm in ein Textfeld schreibt, ohne konvertierung. Wenn ich später wieder auf dieses Textfeld zugreife, dann bekomme ich das wieder raus was ich rein geschrieben habe. Ohne Umwandlung.

Wenn du also ein Python-Programm schreibst, das immer nur auf dem selben Computer oder auf Computern mit dem gleichen Betriebssystem und mit der gleichen Ländereinstellung ausgeführt wird, dann musst du dich theoretisch nicht darum kümmern, was du in welchem Encoding in die Access-DB schreibst. Es wird also oft auch funktionieren, ohne dass du dich darum kümmerst.

Wenn das nicht gesichert ist, dann gilt in Python: "Verwende Unicode!"

Alles was von außerhalb des Programmes in das Programm übermittelt wird -- sei es ein Text aus einer Textdatei, eine Kommdanozeileneingabe, ein Text, der von STDIN gelesen wird oder von einer Datenbank kommt -- sollte nach Unicode umgewandelt werden. Damit hat man im Programm immer einen definierten Zustand.

Alles was vom Programm nach außen weitergegeben wird -- also in eine Textdatei geschrieben wird, nach STDOUT geschrieben wird oder in eine Datenbank geschrieben wird -- sollte von Unicode in ein definiertes Ziel-Encoding umgewandelt werden. Viele Datenbankschnittstellen machen das automatisch. Alle Unicode-Texte werden automatisch in das Encoding der Zieldatenbank umgewandelt. Das machen z.B. die Schnittstellen zu SQLite, zu PostgreSQL und auch zu MySQL also ziemlich automatisch. Eine ODBC-Schnittstelle macht das aber nicht. Also müssen wir uns selber darum kümmern, dass die Texte im Encoding in die Datenbank geschrieben werden, das generell von der Datenbank verwendet wird.

Und ein Access, das unter einem deutschsprachigen Windows ausgeführt wird, arbeitet mit "cp1252". Das ist ein Encoding, das dem "iso-8859-15" ziemlich ähnlich ist. Nur ein paar Sonderzeichen unterscheiden sich in der Codenummer der Zeichen.

Woher ich das mit dem cp1252 weiß? Ganz einfach -- ich habe es ausprobiert. Ich habe verschiedenste Encodings in die AccessDB geschrieben und dann die Datenbank mit Access geöffnet. Bei der Einstellung "cp1252" wurden im Access die Umlaute korrekt angezeigt.

Ich habe Unicode-Strings auch direkt in die DB geschrieben, aber beim Auslesen wurde trotzdem nur cp1252 zurück gegeben. pyodbc wandelt also nicht automatisch um.

Hier noch ein Link zu diesem Thema: http://www.python-forum.de/topic-5095.html

Andere Schnittstellen arbeiten ein wenig anders. Hier als Beispiel pySQLite, wie es mit Unicode umgeht: http://www.python-forum.de/topic-6654.html

mfg
Gerold
:-)

PS: Wenn du die Access-Datenbank nicht auch mit Access oder einem anderen Programm weiterverarbeiten musst, dann gibt es **keinen** Grund, unbedingt eine Access-Datenbank zu benutzen. Unter Python ist **SQLite** die Wahl als Ersatz für Access.

.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

Mittwoch 21. November 2007, 17:00

@gerold: Hattest Du denn ODBC auch konfiguriert? Das ist ja nochmal eine Schicht zwischen Datenbank und Python-Modul.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 21. November 2007, 19:12

BlackJack hat geschrieben:@gerold: Hattest Du denn ODBC auch konfiguriert? Das ist ja nochmal eine Schicht zwischen Datenbank und Python-Modul.
Hallo BlackJack!

Ich hatte mehrere Varianten ausprobiert:
- /etc/odbc.ini
- ~/odbc.ini
- Direkteingabe des DSN wie im Beispiel, mit verschiedenen Treiber-Zeichenfolgen und Datei-Zeichenfolgen. Aber irgendwie hat er auch die Abschnitte in den odbc.ini-Dateien nicht gefunden. :K

Muss man noch etwas einstellen?

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Dienstag 3. Februar 2009, 09:19

Hallo!

Es hat sich eine Änderung beim Verhalten von pyODBC/Access/Windows/(ich weiß nicht) ergeben. pyODBC scheint jetzt selbständig die Unicode-Strings in das von Access verwendete Encoding umzuwandeln. Beim Auslesen bekommt man jetzt auch Unicode zurück, ohne sich selbst darum kümmern zu müssen.

Der geänderte Beispielcode ist unter http://paste.pocoo.org/show/102548/ zu finden.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten