Datei für executemany erstellen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

Hallo

ich bin neu hier im Forum und Einsteiger in Python. Ich versuche mit executemany sehr viele Daten in eine Datenbank zu schreiben. Daher versuche ich, leider bisher vergebens, mir meinen Datensatz in einer Forschleife zusammenzubauen, den ich dann an cur.executemany übergeben kann. Ich weiß im Prinzip wie die Datei aussehen muss, hab aber keinen Schimmer, wie ich das zusammenbauen kann.

Im Prinzip soll es wie hier sein (Am Ende der Seite):
http://www.devx.com/opensource/Article/29071/1954
namedict = ({"first_name":"Joshua", "last_name":"Drake"},
{"first_name":"Steven", "last_name":"Foo"},
{"first_name":"David", "last_name":"Bar"})

cur = conn.cursor()
cur.executemany("""INSERT INTO bar(first_name,last_name) VALUES
(%(first_name)s, %(last_name)s)""", namedict)
Wie kann ich mir das "namedict" zusammenbauen.

Bisher habe ich das hier versucht:

Code: Alles auswählen

#declaration
data = dict()
#forschleife

data[i]={'id':script['id'],'messwert':script['messwert'],'zeitstempel':script['zeitstempel']}
i=i+1
Nur so habe ich in meinem data auch die Keys stehen. Wie muss ich das am besten machen? Ich hoffe es kann mir jemand helfen
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie sieht denn deine Datenstruktur aus? Du zeigst uns ja leider nicht viel und nicht mal lauffähiges. Bisher kann man nur sehen, dass Du ein Dictionary namens `script` bereits hast. Und aus diesem holst Du Dir drei Schlüssel und baust Dir ein neues Dictionary zusammen, welches Du dann in ein anderes Dictionary unter dem Schlüssel `i` (wo immer das her kommt) packst.

Ohne Deine Ausgangsdatenstruktur zu kennen, können wir Dir da kaum helfen!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

Hi Hyperion,
danke für Deine schnelle Antwort.

"i" ist im Prinzip nur ein Indexschlüssel, damit ich ein Dictionary mit allen Daten erzeugen kann. Ich zähle i ja hoch. Also hat i den Wert von 0 - 3717. Aber es ist glaub ich falsch ein Dictionary zu erstellen. Eigentlich müsste ich ein Tupel erstellen, aber ich weiß nicht wie ich das in einer for-schleife erstellen kann, da es ja nicht editierbar ist. :K

Was meinst Du denn mit Datenstruktur?
Das hier?

Code: Alles auswählen

script = dict()
script['messwert'] = None
script['id']  = None
script['zeitstempel']= None
data = dict()
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Einen durchgängigen numerischen Index sollte man eigentlich nie als Schlüssel für ein Dictionary nutzen - den kann man sich mittels `enumerate` immer für eine Liste bswp. erzeugen lassen. Das nur am Rande.

Code: Alles auswählen

Was meinst Du denn mit Datenstruktur?
Na, die Struktur, in der Deine Daten im Moment vorliegen :K

Du schreibst, dass Du viele Daten mittels `executemany` in eine DB kloppen willst. Wie liegen die aktuell vor. Du willst sie ja von der aktuellen Datenstruktur in ein Tupel von Dictionaries überführen. Ohne das Ausgangsformat zu kennen, können wir Dir kaum helfen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

okay, ich versuchs nochmal.
ich lese mehrere *.csv-dateien ein, hole mir da die datenraus

Code: Alles auswählen

liste = open(os.path.join('/tmp/', name), "r")
zeilen = liste.read().split("\n")
liste.close()
for jedezeile in [zeile for zeile in zeilen if len(zeile) is not 0]:
          teile = jedezeile.split(";")
          script['id'] = teile[1]
          script['messwert'] = teile[2]
          script['zeitstempel'] = teile[3]
          data[i]={'id':script['id'],'messwert':script['messwert'],'zeitstempel':script['zeitstempel']}
           i=i+1
cur.executemany("INSERT INTO tbl_measurement (id, measurement, time) VALUES (%(id)s, %(messwert)d, %(zeitstempel)s)", data)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wir haben für Quellcode spezielle Python-Code-Tags. Bitte benutze die doch :-)

Also zu aller erst: Wieso eigentlich `executemany`? Du könntest doch direkt nach dem Lesen einer Zeile ein einfaches `execute` ausführen - das ist im Falle von einer großen Datenmenge sowieso besser, da Du sonst alle Daten komplett in den Speicher laden musst!

Zum Code:

1.) Es gibt in Python ein CSV-Modul. Das ist zwat in einigen Punkten nicht schön (kein Support for Unicode out-of-the-box, Work-around aber in der Doku)¹, aber bietet sich dennoch an. Vor allem gibt es da einen `DictReader`, der Dir die Daten gleich in ein passendes Dictionary packt.

2.) Dateien solltest Du mit dem `with open() as handler`-Idiom öffnen. Damit ist sichergestellt, dass die Datei auf jeden Fall (automatisch) geschlossen wird. Beispiele dazu finden sich auch im `csv`-Modul.

¹ Ich sehe grad, dass das in Python3 wohl gefixt ist; also gilt das nur für Python 2.x
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
deets

froeschchen hat geschrieben: len(zeile) is not 0
Woher hast du das denn? Der is-Operator ist nicht fuer den Vergleich von Zahlenwerten gedacht. Das funktioniert nur durch Zufall, als Implementationsdetail von CPython. Bitte benutz fuer sowas den ==-Operator.

Code: Alles auswählen

>>> a = 1000000
>>> b = 1000000
>>> a is b
False
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

Ich hab eigendlich das code-Ding benutzt.... :oops:

Es hat sich leider herausgestellt, dass die einzelnen inserts zu lange brauchen, daher wollte ich das mit prepared statements machen und alles auf einmal. Kannst Du mir dabei denn auch helfen? Ich werde mal schaun, ob ich mit dem csv-Modul zurande komme.
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

@deets

Es stehen ja nicht nur Zahlenwerte drin, sondern ich prüfe, ob überhaupt was drin steht. Egal was.
Wenn das nicht gut ist, wie kann ich denn abfragen, ob die zeile nicht leer ist?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

froeschchen hat geschrieben:Ich hab eigendlich das code-Ding benutzt.... :oops:
Aber nicht das spezielle ;-)
froeschchen hat geschrieben: Es hat sich leider herausgestellt, dass die einzelnen inserts zu lange brauchen, daher wollte ich das mit prepared statements machen und alles auf einmal. Kannst Du mir dabei denn auch helfen? Ich werde mal schaun, ob ich mit dem csv-Modul zurande komme.
Also ich bezweifel ja irgend wie, dass das mit `executemany` eine Lösung darstellt... denn wenn das so lange dauert, handelt es sich vermutlich um eine große Anzahl an Daten. Das ist immer wenig optimal komplett im Speicher zu erledigen.

Also Du musst eben eine Liste erstellen und in der Schleife dann mit Dictionaries befüllen. Das sind doch absolute Grundlagen!

Code: Alles auswählen

data = []
for foo in csv...:
    data.append({"id":foo["id"], ...})
# hier hast Du dann eine Liste mit allen Dictionaries der Daten.
Ich denke der `DictReader` wäre da eine große Hilfe beim Parsen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
froeschchen
User
Beiträge: 6
Registriert: Montag 28. November 2011, 12:29

cool, vielen Dank, das wars tatsächlich :D

Ich hab irgendwie den Wald vor lauter Bäumen nicht mehr gesehen. Dann sieht man manchmal auch nicht das einfachste!

DANKE, DANKE, DANKE
deets

@froeschchen

Es geht nicht darum, was in der Liste *drin* steht. Sondern was die Funktion "len(liste)" zurueckliefert. Das ist die Laenge der Liste, und das ist eine Zahl.

Letztlich kannst du auch nur

if liste:

schreiben, denn Python ist so definiert, dass leere Listen in if-Abfragen als "falsch" gewertet werden.
Antworten