Einige Fragen zu SQLite

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
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
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

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).
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
querdenker
User
Beiträge: 424
Registriert: Montag 28. Juli 2003, 16:19
Wohnort: /dev/reality

'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
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

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 """
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
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

[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.
querdenker
User
Beiträge: 424
Registriert: Montag 28. Juli 2003, 16:19
Wohnort: /dev/reality

SchneiderWeisse hat geschrieben:...
- du connectest bei jedem Query mit der Datenbank neu, das braucht unnötig Zeit
...
Sh**, den habe ich nicht gesehen :oops:
heiliga horsd

Kann es sein, dass das %s nicht funktioniert, weil hier Python 3 läuft?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
heiliga horsd

Für Format brauch ich doch dann ein Dictionary oder? Irgendwie versteh ich das Formatierungs-Durcheinander nicht mehr... :cry:
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.
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

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?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
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/
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?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

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.
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/
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

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...
Antworten