SQLite Syntax

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Eigentlich dachte ich, ich beherrsche SQL ganz gut, allerdings auf Firebird. Versuche mich gerade einmal in das Thema Datenbank unter Python einzuarbeiten, scheitere aber schon an einem simplen SELECT. :( Als Basis dient mir die Datenbank von Digikam4.

Code: Alles auswählen

#!/usr/bin/env python

"""1st Test in SQLite
"""

import sqlite3
import sys

DBPATH='/usr/data/digikam/digikam4.db'


try:
    conn = sqlite3.connect(DBPATH)
    c=conn.cursor()
except: //natürlich noch ausbaufähig!!
    print('Error')
    sys.exit

c.execute('''select * from Albums
                           order by caption
                           limit 20;''')

for item in c.fetchall():
    print item
    
conn.close()
bring folgende Ausgabe

Code: Alles auswählen

(1, 1, u'/', u'2016-02-03', None, None, None)
(9, 1, u'/Logo', u'2012-12-12', None, None, None)
(25, 1, u'/Poster', u'2013-06-07', None, None, None)
(26, 1, u'/Project20110918 Weddingstedt', u'2011-09-18', None, u'xyz', None)
(27, 1, u'/Project20110918 Weddingstedt/NEF', u'2011-09-18', None, u'xyz', None)
(28, 1, u'/Project20110918 Weddingstedt/bibble', u'2011-10-07', None, u'xyz', None)
(29, 1, u'/Project20110919 Signe', u'2012-05-17', None, u'Portrait', None)
(30, 1, u'/Project20110919 Signe/Grafik', u'2012-05-17', None, u'Portrait', None)
(31, 1, u'/Project20110919 Signe/NEF', u'2012-05-17', None, u'Portrait', None)
(32, 1, u'/Project20110919 Signe/RT4', u'2012-05-17', None, u'Portrait', None)
(33, 1, u'/Project20110919 Signe/bibble', u'2011-09-19', None, u'Portrait', None)
Es gibt diverse Ordner welche die Zeichenkette "Signe" im Namen habe. Ergänze ich das Ganze um "where caption like '%Signe%', dann bekomme ich nur eine leere Ausgabe.

Code: Alles auswählen

c.execute('''select * from Albums
                           where caption like "%Signe%"
                           order by caption
                           limit 20;''')
Was mache ich hier falsch?
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Sorry, hat sich erledigt! Wenn man dann die falsche Spalte (caption) abfragt, kann es ja nicht funktionieren :oops:
BlackJack

Zum ``except: //natürlich noch ausbaufähig!!``: Das ist einfach nur unsinnig! Du ersetzt *jede* Ausnahme einfach um ein nichtssagendes 'Error' und einen Programmabbruch. Also letzteres nur wenn Du das Programm da auch wirklich abbrechen würdest, statt nur die Funktion zu ermitteln ohne sie aufzurufen. Der Gedanke zählt… ;-)

Lass so eine ”Behandlung” einfach weg und es wird ausgegeben *was* zum Programmabbruch geführt hat. Genau dafür sind Ausnahmen doch da. Nicht um sie zu unterdrücken wenn man nicht weiss was man damit besseres machen soll.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

@BlackJack. Habe gerade erst angefangen mit Python und SQLite. Ist mir klar dass das so nicht stehen bleiben kann. Was z. B. wenn die Datenbank nicht existiert? Die Fehlermeldung kommt dann erst beim c.execute() und sagt aus, dass die Tabelle nicht existiert. Stimmt ja, aber die Datenbank ist auch nicht vorhanden. Das ist mir persönlich zu spät. Also werde ich es weiter ausbauen.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@hans: die Datenbank existiert, weil falls sie nicht existiert, wird sie von SQLite erzeugt. Und bevor man eine fehlerhafte Fehlerbehandlung macht, sollte man lieber gar keine machen, vor allem wenn das Programm dann weiterläuft und in der nächsten Zeile mit einem NameError abbricht.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Ach Kinners, nun seid mal nicht päpstlicher als der Papst :wink:

Waren bisher doch nur erste Versuche in SQLite und nach langer Zeit auch wieder mit Python bevor man in die Vollen geht. Aber zur Beruhigung, habe mal etwas daran gefeilt.

Code: Alles auswählen

import sqlite3
import sys
import os

DBPATH='/usr/data/digikam/digikam4.db'

try:
    if  not os.path.isfile(DBPATH):
        raise(FileNotFoundError)
    if not os.path.getsize(DBPATH) > 0:
        raise(FileNotFoundError)
except FileNotFoundError:
    print('file  ', DBPATH, ' not found')
    sys.exit()
Übrigens in einer GUI Umgebung würde ich natürlich kein sys.exit() machen.

Dann stürze ich mich einmal auf das gettext Modul, bevor ich dann mal überlege was ich dann alles in Zusammenhang mit QT anstellen kann.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@hans: beim Programmieren kommt es auf Exaktheit an. Fehlende Klammern machen da einen entscheidenden Unterschied. raise ist keine Funktion und sollte auch nicht als solche geschrieben werden. Deine Tests verhindern auch nicht, dass ungeeignete Datenbanken benutzt werden. Wenn Du sicherstellen willst, dass eine Tabelle existiert, solltest Du auch deren Existenz prüfen und nicht irgend etwas anderes.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

weil päpstlich sein so toll ist: die Fehlerbehandlung

Code: Alles auswählen

if not os.path.getsize(DBPATH) > 0:
    raise(FileNotFoundError)
ist irreführend bzw. falsch, es wird der falsche Fehler ausgelöst.

Wenn einen Datei dir Größe null hat, existiert sie trotzdem. Hier solltest du also besser ein "FileSizeError" oder so was in der Art auslösen.

Abgsehen davon, kannst du die if-Abfrage auch vereinfachen:

Code: Alles auswählen

if os.path.getsize(DBPATH) == 0:
Gruß, noisefloor
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

hans hat geschrieben:Waren bisher doch nur erste Versuche in SQLite und nach langer Zeit auch wieder mit Python bevor man in die Vollen geht. Aber zur Beruhigung, habe mal etwas daran gefeilt.
Das Problem ist dadurch nicht gelöst weil zwischen der Prüfung ob die Datei existiert und dem öffnen der Datei, diese gelöscht werden könnte.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Jetzt interessiert mich aber doch wie es richtig ist. Bei meinen Spielereien hatte ich versehentlich eine 0 Byte große Datei angelegt. Die Datei existiert also kann das keine SQLite Datenbank sein, denn jede SQLite Datenbank hat die Tabelle sqlite_master welche u. a. die Definitionen der in der Datenbank angelegten Tabellen enthält. Da es mir in dem Beispiel ausschließlich um Select-Statements geht, muss die Datenbank existieren und Daten enthalten.

Wenn die Datei existiert, dann ist aber noch immer nicht gesagt, dass es sich um eine SQLite Datenbank handelt. Der Systemkommando file existiert soviel wie ich weiß ausschließlich unter Linux / Unix.

Das Problem scheint mir zu sein, dass eine in Connection angegebene Datenbank automatisch erzeugt wird, sobald man CREATE TABLE aufruft. Ich kenne es von Firebird nur so, dass eine Datenbank als erstes mit CREATE DATABASE ... erzeugt werden muss. Entsprechendes habe ich in der Doku von SQLite bisher nicht gefunden.

Bei Connect und Cursor wird keine Exception ausgelöst, egal ob die in Connect angegebene Datei existiert oder nicht. Die erste Fehlermeldung kommt erst beim Execute, was in meinen Augen eigentlich zu spät ist. Kann man bereits beim Erstellen der Connection / des Cursors etwas abfangen? Wenn ja, wie?
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

um schon bei `connect()` eine Exception bei einer nicht existierenden DB zu bekommen, musst du anders connecten. Das steht in Teilen in der Python3 SQLite Doku, siehe https://docs.python.org/3/library/sqlit ... e3.connect am Ende des Abschnitts.

Beispiel:

Code: Alles auswählen

>>> import sqlite3
>>> db_1 = sqlite3.connect('file:non_exisiting.db?mode=rw', uri=True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
sqlite3.OperationalError: unable to open database file
>>> db_2 = sqlite3.connect('some_db.db')  #Datei existiert nicht, wird aber angelegt
>>> cursor = db_2.cursor()
>>> cursor.execute('CREATE TABLE foo (something text)')
<sqlite3.Cursor object at 0x7fc183fd41f0>
>>> db_2.commit()
>>> db_1_next_try = sqlite3.connect('file:some_db.db?mode=rw', uri=True)  #Datei existiert, darum gibt's jetzt keine Exception
>>>
War mir bis Ebene aber auch nicht bekannt, dass das so funktioniert :-)

Gruß, noisefloor
BlackJack

@hans: Man muss halt wirklich das prüfen was man wissen möchte: Ob die Tabelle existiert. Es kann sein, das es dafür ein Pragma gibt, das weiss ich aus dem Kopf jetzt nicht, oder man schaut in der ”Metatabelle” nach ob es die Tabelle gibt, oder man fragt etwas aus dieser Tabelle ab.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Danke an alle für die Aufklärung, obwohl es vordergründig nicht um Python ging. Hat mir sehr geholfen.

Das mit den URI Files hatte ich zwar gesehen, aber nicht wirklich verstanden. Na dann kann ich ja mal in die Tasten greifen und muss euch hoffentlich nicht so oft nerven. Wenn's was wird, stelle ich es vor. Versprochen. Größte Baustelle wird mit Sicherheit QT sein.
Antworten