execute und Platzhalter

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hallo!

Folgender Code treibt mich in den Wahnsinn:

Code: Alles auswählen

fields = data_dict.keys()
values = data_dict.values()
placeholder = "%s"
fieldlist = ",".join(fields)
placeholderlist = ",".join([placeholder] * len(fields))
query = "insert into 'Adressdaten' (%s) values (%s)" % (fieldlist, placeholderlist)

curser.execute(query, values) # Hier stört sich das Script
Fehler:

Code: Alles auswählen

    curser.execute(query, values)
sqlite3.OperationalError: near "%": syntax error
Ich fasse kurz zusammen was ich mache: Ich hab ein Dictionary mit "Spaltenname":"DatenZumSpeichern". Der Schnipsel füllt dann das query mit den Spalten und der passenden Anzahl von Platzhaltern für die späteren Daten. Bis hierhin klappt alles, das haben meine Tests ergeben.

query ist wie gewollt ein String, values eine Liste.

Im execute sollte er mir aber nun die Platzhalter im query durch die Daten in den values ersetzen. Das mag er aber aus irgendeinem, mir nicht ersichtlichen Grund nicht.

Habt ihr eine Idee? Sehe ich den Wald vor lauter Bäumen nicht?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Generell erst einmal:
[wiki]Parametrisierte SQL-Queries[/wiki]

Die Parameter bitte nicht so zusammenfrickeln, sondern besser einzeln übergeben.

Du willst imho mehere Inserts ausführen. Das solltest Du imho mit einer Schleife lösen.
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hallo,

ja, das ganze läuft in einer Schleife. Ich muss mir angewöhnen und genauer zu beschreiben was ich vor habe :)

Also. Das soll im Endeffekt eine Funktion werden, die Daten aus einer CSV ausliest. In der ersten Zeile stehen die Namen der späteren Spalten inder Datenbank.
Der Funktion werden einige dieser Namen mitgegeben, daraus wurstet das Script dann eine Datenbank und soll sie füllen. Da die Anzahl und die Namen der Spalten flexibel sind, muss ich das so machen wie oben.

Im Endeffekt entspricht meine Version denen aus deinem Link, oder?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

start_with_python hat geschrieben: ja, das ganze läuft in einer Schleife. Ich muss mir angewöhnen und genauer zu beschreiben was ich vor habe :)
Dann solltest Du die auch angeben ;-)
Der Funktion werden einige dieser Namen mitgegeben, daraus wurstet das Script dann eine Datenbank und soll sie füllen. Da die Anzahl und die Namen der Spalten flexibel sind, muss ich das so machen wie oben.
Du musst doch aber wissen, in welche Tabelle Du was schreibst. Also kannst Du das dann doch auch entsprechend mappen.
Im Endeffekt entspricht meine Version denen aus deinem Link, oder?
Hast Du Dir das auch durchgelesen? Schau es Dir noch mal genau an :-)

Eine mögliche Alternative wäre für Dich auch executemany(). Damit sparst Du Dir die Schleife bei vielen gleichartigen insert-Statements. In der Python-Doku zu SQLite gibts da Beispiele.

Auf jeden Fall musst Du Dir im klaren sein, welche Struktur Deine Parameter haben müssen und welche sie tatsächlich haben. Das war nämlich der Hauptfehler auf Sprachebene in Deinem Snippet.
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Hyperion hat geschrieben:
start_with_python hat geschrieben: Im Endeffekt entspricht meine Version denen aus deinem Link, oder?
Hast Du Dir das auch durchgelesen? Schau es Dir noch mal genau an :-)
Ja, finde ich doch. Hat doch große Ähnlichkeiten mit dem "format"-Beispiel, oder nicht?

Ich habe das Problem allerdings nun gelöst bekommen. Es lag ganz einfach an dem falschen "placeholder". Das darf bei SQL anscheinend nicht "%s", sondern muss ein "?" sein.

So klappt es also nun:

Code: Alles auswählen

            fields = data_dict.keys()
            values = data_dict.values()
            placeholder = "?"
            fieldlist = ",".join(fields)
            placeholderlist = ",".join([placeholder] * len(fields))
            query = "insert into 'Adressdaten' (%s) values (%s)" % (fieldlist, placeholderlist)

            cursor.execute(query, values)
            print "Erfolg!"
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wobei ich immer noch keine Schleife bei Dir sehe? An welcher Stelle iterierst Du denn nun über die Daten?
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

Der funktion wird eine Liste mit den Spaltennamen übergeben, die wir haben wollen (in der CSV-Datei gibt es noch mehr Spalten, die ich aber nicht haben will):

Code: Alles auswählen

column=["ANREDE", "NAME", "VORNAME", "LAND", "PLZZ", "ORT", "STRASSE",  "TELEFON", "TELEFAX", "TELEFON2", "BEMERKUNG", "STICHWORT1",  "STICHWORT2", "ZUSATZ1", "ZUSATZ2", "ERFDAT", "L_DAT", "RECORDID"]
So schaut es mit der Schleife aus:

Code: Alles auswählen

 
reader = csv.reader(open(data, "rb"), delimiter=";")
row_count = 0
column_check=[]
for row in reader:
        #~ Die Erste Zeile enthaelt die SPaltennamen. Wir suchen die Nummern der Spalten
        if row_count <= 0:
            print "Spalten mit Vorgabe abgleichen..."
            col_count = 0
            for i in row:
                if i in column:
                    column_check.append(col_count)
                col_count += 1
            if len(column_check) != len(column):
                sys.exit("Fehler: Die Ausgangsdatei enthaelt nicht alle \
                benoetigten Spalten! Programm wird beendet!")

        #~ Jetzt die Eingabe der Datensaetze die benoetigt werden
        else:

            col_count = 0
            col_index = 0
            data_dict = {}
            error_log = 0
            #~ print "-----"
            for i in row:
                if col_count in column_check:
                    #~ print "%s ist da und bezeichnet %s" % (column[col_index], i)
                    data_dict[column[col_index]] = i.decode("utf-8")
                    col_index += 1
                col_count += 1

            try:
                fields = data_dict.keys()
                values = data_dict.values()
                placeholder = "?"
                fieldlist = ",".join(fields)
                placeholderlist = ",".join([placeholder] * len(fields))
                query = "insert into 'Adressdaten' (%s) values (%s)" % (fieldlist, placeholderlist)

                cursor.execute(query, values)
                #~ print "Speichere Datensatz", data_dict['VORNAME'],  data_dict['NAME'], " - Erfolg!"
                print ".",
                sys.stdout.flush()
                time.sleep(0.001)
            except:
                print "\nFehler beim Import von Datensatz: ", data_dict['VORNAME'],  data_dict['NAME'], "\n"
                error_log += 1
        row_count += 1
print "\nCheck: ", column_check
connection.commit()
print " * Import beendet"
print " * Fehler: ", error_log

Funktioniert wunderbar :)
(Ich weiß, hält sich noch nicht an die PEP8. Nicht böse sein!)
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
lunar

Wofür "sys.stdout.flush()" und wofür "time.sleep()"?

Ferner solltest du den Commit einen finally-Block stellen, damit Daten auch korrekt geschrieben werden, wenn eine Ausnahme eintritt. Apropos Ausnahme: Wenn schon ein "except" ohne konkrete Ausnahme, dann wenigstens mit Ausgabe des Tracebacks! Eigentlich solltest du aber mindestens "Exception" angeben, denn so fängst du auch einen KeyboardInterrupt und einen SystemExit ab.
start_with_python
User
Beiträge: 41
Registriert: Samstag 20. Juni 2009, 18:12

lunar hat geschrieben: Wofür "sys.stdout.flush()" und wofür "time.sleep()"?
Überbleibsel. Ich mag es, wenn ich den Fortschritt "sehen" kann. Unnütz und verlangsamend, aber ich mags :)
lunar hat geschrieben: Ferner solltest du den Commit einen finally-Block stellen, damit Daten auch korrekt geschrieben werden, wenn eine Ausnahme eintritt. Apropos Ausnahme: Wenn schon ein "except" ohne konkrete Ausnahme, dann wenigstens mit Ausgabe des Tracebacks! Eigentlich solltest du aber mindestens "Exception" angeben, denn so fängst du auch einen KeyboardInterrupt und einen SystemExit ab.
Ok, danke. Das werde ich mit einbauen.

lunar hat geschrieben:SystemExit
== sys.exit() ?
Oder auch aus anderen Gründen?
Grüße[b]
start_with_python[/b]

Lust auf [url=https://www.dropbox.com/referrals/NTE5OTQ5Mjk5]DropBox[/url]? (RefLink)
lunar

Ja, SystemExit wird durch sys.exit() ausgelöst.
Antworten