Seite 1 von 2

Einige Fragen zu SQLite

Verfasst: Dienstag 16. Februar 2010, 18:33
von heiliga horsd
Hallo,

ich mache erste Gehversuche mit SQLite. Ich hatte bereits ein paar Probleme, die ich aber (hoffentlich) gelöst habe (bis jetzt funktioniert es).

Mein momentanes Problem basiert eher auf fehlender Erfahrung, und zwar:
Ich hab 26335 Datensätze, alle maximal 40 Zeichen lang. Mein Programm braucht nun schon 20 Minuten zum befüllen der Datenbank und ist immer noch nicht fertig - ist das normal?


Lg HH

Verfasst: Dienstag 16. Februar 2010, 18:40
von nemomuk
Das scheint wohl etwas zu lang zu sein, außer du machst irgendwas konkretes mit dne Daten bevor du sie in die Datenbank schreibst. Dazu bräuchte man allerdings mehr Infos (Code, Daten).

Verfasst: Dienstag 16. Februar 2010, 18:43
von heiliga horsd
Hallo,

ich versuche mich grade zu Übungszwecken am Auslesen, Verarbeiten und speichern von Daten, später will ich diese dann auch sortiert aufrufen und ausgeben können.

Als Grundlage habe ich vom Browserspiel Stämme die Weltdaten der Spieler verwendet. Mein Python-Programm sieht so aus:

Code: Alles auswählen

import gzip
import urllib.parse
import sqlite3

def database_player(_id, name, ally, villages, points, rank):
    connection = sqlite3.connect("Staemme-Datenbank.db")
    cursor = connection.cursor()
    try:
        try:
            sql = "CREATE TABLE Staemmespieler(_id INTEGER PRIMARY KEY,"\
                  "name TEXT, ally TEXT, villages INTEGER,"\
                  "points INTEGER, rank INTEGER)"
            cursor.execute(sql)
        except sqlite3.OperationalError:
            sql = "INSERT INTO Staemmespieler VALUES('"+_id+"','"+name+"','"\
                +ally+"','"+villages+"','"+points+"','"+rank+"')"
        cursor.execute(sql)
        connection.commit()
    except Exception:
        connection.close()
    
    
    

    

with gzip.open("player.txt.gz") as f:
    inhalt = list(map(urllib.parse.unquote_plus,
                      f.read().decode("iso-8859-15").split("\n")))

length = len(inhalt)
print(length)
for i in range(0, length-1):
    _id = (str(inhalt[i].split(',')[0]))
    name = (str((inhalt[i].split(',')[1])))
    ally = (str((inhalt[i].split(',')[2])))
    villages = (str((inhalt[i].split(',')[3])))
    points = (str((inhalt[i].split(',')[4])))
    rank = (str((inhalt[i].split(',')[5])))
    database_player(_id, name, ally, villages, points, rank)
    
Das auselesen und anzeigen der Spielerdaten funktioniert in gewohnter Geschwindigkeit, ich persönlich würde das also als Fehlerquelle ausschließen.

Lg

Verfasst: Dienstag 16. Februar 2010, 19:14
von querdenker
'n paar Sachen, ohne weiter getestet zu haben:
- Löse mal deine verschachtelten try..except-blöcke auf, so das die getrennt stehen
- gehe mal deinen Code in Ruhe durch und überlege dir, wann du wo auf welchen except wie reagierst. Es ist vom Ablauf her schlicht schwachsinnig bei jedem Aufruf der function database_player erst zu versuchen die Tabelle zu erstellen.
- gleiche mal deine datentypen in der Table-Def mit denen aus deiner for...Schleife ab. Da passt auch was nicht.

hth

Verfasst: Dienstag 16. Februar 2010, 19:20
von nemomuk

Code: Alles auswählen

import gzip
import urllib.parse
import sqlite3


connection = sqlite3.connect("Staemme-Datenbank.db")

cursor = connection.cursor()
sql = "CREATE TABLE Staemmespieler(_id INTEGER PRIMARY KEY,"
      "name TEXT, ally TEXT, villages INTEGER,"
      "points INTEGER, rank INTEGER)"
cursor.execute(sql)

with gzip.open("player.txt.gz") as f:
    inhalt = f.read().decode("iso-8859-15")

for line in inhalt.split("\n"):
    sql = "INSERT INTO Staemmespieler VALUES(%s, %s, %s, %s, %s, %s)"
    cursor.execute(sql, list(map(urllib.parse.unquote_plus, line.split(','))))
    connection.commit()

connection.close()
Das sollte so theoretisch funktionieren und ist etwas überarbeitet.

Ein paar Anmerkungen:
- verwende parametrisierte SQL-Queries
- überleg dir eine bessere try-except Strategie
- man kann direkt über die Elemente einer Liste iterieren
- du connectest bei jedem Query mit der Datenbank neu, das braucht unnötig Zeit
- """ Mehrzeiliger
String """

Verfasst: Dienstag 16. Februar 2010, 19:34
von heiliga horsd
Hallo ihr beiden,

Erstmal danke für die Antworten.
SchneiderWeisse hat geschrieben:
Das sollte so theoretisch funktionieren und ist etwas überarbeitet.
Leider nein:
cursor.execute(sql, list(map(urllib.parse.unquote_plus, line.split(','))))
sqlite3.OperationalError: near "%": syntax error
(ist das normal, dass er mir nicht sagt wo GENAU er den fehler fand?)
SchneiderWeisse hat geschrieben:Ein paar Anmerkungen:
- verwende parametrisierte SQL-Queries
Was ist das? :oops:
SchneiderWeisse hat geschrieben: - überleg dir eine bessere try-except Strategie
Danke, das werde ich machen!
SchneiderWeisse hat geschrieben: - man kann direkt über die Elemente einer Liste iterieren
Hmm, daran hatte ich gar nicht gedacht :oops:
SchneiderWeisse hat geschrieben: - du connectest bei jedem Query mit der Datenbank neu, das braucht unnötig Zeit
OK, das wusste ich wirklich nicht, danke!
SchneiderWeisse hat geschrieben:- """ Mehrzeiliger
String """
Das weiß ich, aber ich wusste nicht, ob ich mir da Probleme mit dem Befehl einhandle.


Frage:
Was bedeutet das %s bzw. was bedeuten die Teile mit % davor überhaupt? Lese das hier immer wieder aber hab noch nirgends eine Erklärung dazu gefunden Question

Verfasst: Dienstag 16. Februar 2010, 19:41
von nemomuk
[wiki]Parametrisierte SQL-Queries[/wiki]

[wiki]String-Formatter[/wiki]

Das ganze sieht übrigens ziemlich stark nach einer CSV-Struktur aus, siehe csv-Modul.

Den Fehler kann ich ohne Sicht auf die Daten nicht nachvollziehen. Irgendein Fehler im Query, aber das solltest du mit der obi9gen Wiki-Seite selbst hinkriegen.

Verfasst: Dienstag 16. Februar 2010, 19:53
von querdenker
SchneiderWeisse hat geschrieben:...
- du connectest bei jedem Query mit der Datenbank neu, das braucht unnötig Zeit
...
Sh**, den habe ich nicht gesehen :oops:

Verfasst: Dienstag 16. Februar 2010, 19:57
von heiliga horsd
Kann es sein, dass das %s nicht funktioniert, weil hier Python 3 läuft?

Verfasst: Dienstag 16. Februar 2010, 21:09
von cofi
heiliga horsd hat geschrieben:Kann es sein, dass das %s nicht funktioniert, weil hier Python 3 läuft?
Nein, aber seit 2.6 sollte man die `format` Methode bevorzugen.

Verfasst: Dienstag 16. Februar 2010, 21:19
von heiliga horsd
Für Format brauch ich doch dann ein Dictionary oder? Irgendwie versteh ich das Formatierungs-Durcheinander nicht mehr... :cry:

Verfasst: Dienstag 16. Februar 2010, 21:47
von cofi

Verfasst: Dienstag 16. Februar 2010, 22:07
von BlackJack
Hallo!? Das ist die falsche Baustelle. `format()` ist für Zeichenketten, wir haben hier SQL wo man die Werte eben *nicht* mittels Zeichenkettenformatierung reinbringen sollte.

SQLite will '?' statt '%s' als Platzhalter.

Verfasst: Dienstag 16. Februar 2010, 22:10
von nemomuk
BlackJack hat geschrieben:Hallo!? Das ist die falsche Baustelle. `format()` ist für Zeichenketten, wir haben hier SQL wo man die Werte eben *nicht* mittels Zeichenkettenformatierung reinbringen sollte.

SQLite will '?' statt '%s' als Platzhalter.
Jo, das stimmt, irgendwie hatte ich das falsch in Erinnerung. Kann es sein, dass andere Datenbank-Module andere Platzhalter verwenden?

Verfasst: Dienstag 16. Februar 2010, 22:24
von cofi
Nein, das PEP, d.h. das Datenbank-Interface , laesst mehrere Stile zu (wie die Wiki-Seite auch richtig beschreibt)
http://www.python.org/dev/peps/pep-0249/

Ich haette erwaehnen sollen, dass meine Posts sich auf das Formatting bezogen und nicht, ich wiederhole: NICHT auf Datenbank-Queries.

Verfasst: Mittwoch 17. Februar 2010, 11:27
von heiliga horsd
Also, mit den Fragezeichen funktioniert es nun (danke für die Links, werde ich mir nochmal durchlesen).

Leider bekomme ich nachdem die Datenbank 64kb groß ist folgende Fehlermeldung:
cursor.execute(sql, list(map(urllib.parse.unquote_plus, line.split(','))))
sqlite3.OperationalError: unable to open database file
Hier nochmal der Quelltext:
http://paste.pocoo.org/show/179205/

Verfasst: Mittwoch 17. Februar 2010, 12:51
von heiliga horsd
Erstmal sorry für meine Doppelposts :oops:

So sieht es also jetzt aus:
http://paste.pocoo.org/show/179227/

Ich bekomme aber immer noch teilweise Fehlermeldungen, zum Teil, dass der Primary Key eindeutig sein muss (wenn ich dann das Programm ein zweites mal starte funktioniert es) und dass die Datenbank gesperrt ist (obwohl ich die Verbindung doch eigentlich getrennt habe) - wenn ich dann Python neu starte läuft hier auch wieder alles astrein.

Kann mir das jemand erklären warum sich das so verhält?

Verfasst: Mittwoch 17. Februar 2010, 13:00
von ms4py
Hier ein paar Tipps:
- Du solltest die Verbindung in einem try..finally Block schließen.
- Es gibt ``str.splitlines()``
- Normalerweise sollte man nie die allg. ``Exception`` abfangen, sondern immer die konkrete
- Eine Lösung mit ``executemany`` wäre vermutlich eine schnellere Alternative.

BTW: Wie sieht denn die Datei aus? Am besten mal ein paar Zeilen posten.

Verfasst: Mittwoch 17. Februar 2010, 13:11
von heiliga horsd
Danke für deine Antwort!
ice2k3 hat geschrieben:Hier ein paar Tipps:
- Du solltest die Verbindung in einem try..finally Block schließen.
Wie meinst du? Also das ganze Programm in einen try-Block setzen oder wie?
ice2k3 hat geschrieben:- Es gibt ``str.splitlines()``
Wozu ist das gut?
ice2k3 hat geschrieben: - Normalerweise sollte man nie die allg. ``Exception`` abfangen, sondern immer die konkrete
Danke für den Hinweis.
ice2k3 hat geschrieben: - Eine Lösung mit ``executemany`` wäre vermutlich eine schnellere Alternative.
Wo ist der Unterschied zu execute?
ice2k3 hat geschrieben: BTW: Wie sieht denn die Datei aus? Am besten mal ein paar Zeilen posten.
http://paste.pocoo.org/show/179227/

Verfasst: Mittwoch 17. Februar 2010, 13:29
von ms4py
heiliga horsd hat geschrieben:
ice2k3 hat geschrieben:Hier ein paar Tipps:
- Du solltest die Verbindung in einem try..finally Block schließen.
Wie meinst du? Also das ganze Programm in einen try-Block setzen oder wie?
Den Teil nach dem Öffnen der Verbindung und das Schließen dann ins finally.
heiliga horsd hat geschrieben:
ice2k3 hat geschrieben:- Es gibt ``str.splitlines()``
Wozu ist das gut?
Zeilenumbrüche sind nicht immer "\n", zum Teil gibt es auch "\r\n" oder ähnliches.
heiliga horsd hat geschrieben:
ice2k3 hat geschrieben: - Eine Lösung mit ``executemany`` wäre vermutlich eine schnellere Alternative.
Wo ist der Unterschied zu execute?
Das steht in der Doku...
heiliga horsd hat geschrieben:
ice2k3 hat geschrieben: BTW: Wie sieht denn die Datei aus? Am besten mal ein paar Zeilen posten.
http://paste.pocoo.org/show/179227/
Ich meine eigentlich die Textdatei, die du einliest...