SQLite max() Funktion

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
mikanoca
User
Beiträge: 26
Registriert: Dienstag 15. Juni 2010, 11:02

mal ne simple Frage:

Code: Alles auswählen

    def getMaxAlter(self, table):
        sql = 'SELECT max(Alter) from ?'
        try:
            self.cur.execute(sql,(table,))
        except sqlite3.OperationalError as e:
            print("SQL Fehler: ", e.args)
liefert einen Fehler, wenn die Tabelle leer ist. Wie kann ich das umegehen ?
Zuletzt geändert von Anonymous am Mittwoch 20. Februar 2013, 11:49, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@mikanoca: Das ist grundsätzlich schon mal fehlerhaft, weil der Tabellenname kein Wert ist und damit auch nicht durch einem SQL-Platzhalter ersetzt werden darf. Falls das bei Dir funktioniert, ist das undefiniertes Verhalten auf das man sich nicht verlassen kann. Tabellennamen sollten auch nicht variabel sein. Das ist ein „code smell” der in der Regel auf Fehler im Datenbankentwurf hindeutet.

Ansonsten gehst Du mit der Ausnahme doch schon um. Vielleicht nicht auf die vernünftigste Art, denn Fehler einfach mit ``print`` ausgeben, und dann einfach so weitermachen als wäre nichts passiert, ist in den seltensten Fällen eine gute Idee.

Die Frage ist doch was bei einer leeren Tabelle das maximale Alter *ist*? Wenn nicht ein Ausnahmefall. In dem man mit einer Ausnahme reagieren sollte. Also genau das was hier passiert.

Der Methodenname hält sich übrigens nicht an den Style Guide for Python Code.
mikanoca
User
Beiträge: 26
Registriert: Dienstag 15. Juni 2010, 11:02

@BlackJack: Kannst Du mir das mit dem Platzhalter näher erklären ? Meine Annahme war immer, dass ich ein sql-Statement basteln will und mit dem '?' einfach eine Variable einsetze. Dabei ist es nach meinem Dafürhalten unerheblich, ob in der from-clause oder where-clause. Ich lasse mich aber gern eines Besseren belehren.

Der Nachteil bei Deiner Anregung, diesen Fall aus Ausnahme zu behandeln, ist, dass ich damit jeden SQL-Fehler abfange, oder ?
BlackJack

@mikanoca: Die Platzhalter bei SQL-Anweisungen sind nur für Werte gedacht, und die werden entsprechend als Werte escaped/behandelt. Alles andere ausser Werten sollte in SQL-Anweisungen auch nicht variabel sein. Darauf sind SQL-Datenbanken nicht ausgelegt und deshalb sind „variable Tabellennamen” auch ein deutlicher Hinweis auf einen Entwurfsfehler. Das Datenbankschema sollte fix sein.

Die SQL-Funktion `max()` ist hier auch gar nicht das Problem, die liefert bei leeren Tabellen `NULL`, also auf Python-Seite `None`, und keine Ausnahme:

Code: Alles auswählen

In [16]: cur.execute('create table person (id integer primary key, age integer)')
Out[16]: <sqlite3.Cursor at 0x9861720>

In [17]: con.commit()

In [18]: cur.execute('select max(age) from person')
Out[18]: <sqlite3.Cursor at 0x9861720>

In [19]: cur.fetchone()
Out[19]: (None,)
Nochmal zur Namensgebung: `cursor` würde ich in Programmen nicht abkürzen. Die drei zusätzlichen Zeichen bringen niemanden um und man sieht leichter was der Name bedeutet.

Edit: Nochmal zum Datenbankentwurf: Ein Alter in der Form zu speichern ist vielen Fällen auch problematisch, denn ein Alter ist ein Wert der sich mit der Zeit ändert. Darum speichert man üblicherweise den Zeitpunkt 0, also zum Beispiel den Geburtstag, denn der ist fest und das jeweilige aktuelle Alter lässt sich daraus berechnen.
mikanoca
User
Beiträge: 26
Registriert: Dienstag 15. Juni 2010, 11:02

ok, danke.
Dann liegt es wohl tatsächlich an dem variablen Tabellennamen, 'NULL' als Ergebnis ist ja kein sql-Fehler
-> mach ich dann anders.
Antworten