DB-Anfänger - Tabelle mit Variablen anlegen in sqlite3

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Hallo zusammen,

ich möchte mit Python 2.5 eine sqlite3-Tabelle anlegen. Sowohl der Tabellennamen als auch die Spaltennamen habe ich als Variablen verfügbar.

Ich weiss, das ich Einträge dann mittels des ?-Syntaxes machen kann, aber wie bekomm eich die Variablennamen beim anlegen einer Tabelle übergeben?

Danke

BastiL
BlackJack

BastiL: Die '?' sind nur für Werte geeignet. Du wirst also hier einfach eine SQL-Anweisung zum Anlegen der Datenbank als Zeichenkette zusammen bauen müssen.

Oder Du verwendest z.B. SQLAlchemy als Abstraktionsschicht.

Allerdings solltest Du gut aufpassen was alles Böses passieren kann, wenn die Daten von "aussen" kommen und ungeprüft einfach so verwendet werden.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Code: Alles auswählen

def create_table(name, *columns):
    return "create table %s (%s)" % (name, ", ".join(columns))
    
print create_table("t", "x", "y", "z")
Stefan
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Wundere dich übrigens nicht: SQLite legt die Spaltennamen nicht notwendigerweise in der Reihenfolge an, wie du sie definiert hast. Entsprechend sind SELECTs über das Kommandozeilentool äußerst bescheiden zu lesen, wenn etwa die Spalte `id` nicht als erste angezeigt wird, sondern mittendrin. Gemeinsam mit so Eigenheiten wie der Notwendigkeit, Tabellen neu anlegen zu müssen um Spalten entfernen zu können, habe ich SQLite dann auch recht bald den Rücken gekehrt.

Für den Fall, dass deine Tabellen- oder Spaltennamen mit reservierten Schlüsselwörtern kollidieren, lässt sich der Code von sma wie folgt mit zusätzlichen Anführungszeichen erweitern (Spalten wie `foo'bar` solltest du dennoch nicht anlegen ;)):

Code: Alles auswählen

def create_table(name, *columns):
    return "CREATE TABLE '%s' ('%s')" % (name, "', '".join(columns))
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Y0Gi hat geschrieben:SQLite legt die Spaltennamen nicht notwendigerweise in der Reihenfolge an, wie du sie definiert hast.
Hallo Y0Gi!

Das habe ich bis jetzt noch nicht beobachten können. Vielleicht hattest du eine Abstraktionsschicht dazwischen, die das verbockt hat.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

Kann ich auch nicht bestägigen und hege auch den Verdacht, dass da irgendwo ein Python-Dictionary zwischengeschaltet war.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Hmmmm. Na gut, wenn ihr das sagt. Ich *kann* mir vorstellen, dass es eine alte Version von SQLAlchemy (< 0.5, evtl. < 0.4) gewesen sein *könnte*, weil die damals noch nicht die Reihenfolge berücksichtigt hat. Dann nehme ich hiermit alles zurück und behaupte das Gegenteil ;) Die anderen Einschränkungen von SQLite sind allerdings noch vorhanden und manchmal recht nervig.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Ok, so weit klappt es schon mal - danke.

Jetzt möchte ich aber bevor ich die Spalten anlege prüfen, ob die schon da sind. Dazu gibt es so wie ich das sehe das "IF NOT EXIST" SQL-statement ab sqlite 3.3. Allerdings muss ich zu sqlite 3.2 kompatibel bleiben. Wie kann ich so etwas dann machen? Irgendwie kann man doch sicher die Spaltentitel abfragen und dann mit den Strings abgleichen, die ich in meinem Dictionary habe?
Etwas präziser möchte ich den Inhalt eines DIctionaries in der Datenbank ablegen. Der Schlüssel entspricht dem Spaltennamen, der angelegt werden soll falls es noch keine entsprechende Spalte gibt. Der Wert ist dann in der jeweiligen Spalte abzulegen.

Gruß
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

http://www.sqlite.org/sqlite.html

Code: Alles auswählen

sqlite> select * from sqlite_master;
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Ok, jetzt habe ich eine Liste mit Tupeln der Überschriften bekommen. JEtzt versuche ich das mit meinen Strings abzugleichen und bekomme das nicht hin. Ich weiss nicht wie ich mit dem Tupel arbeiten kann....
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BastiL hat geschrieben:Ok, jetzt habe ich eine Liste mit Tupeln der Überschriften bekommen. JEtzt versuche ich das mit meinen Strings abzugleichen und bekomme das nicht hin. Ich weiss nicht wie ich mit dem Tupel arbeiten kann....
Was weißt Du denn nicht? Was hast Du schon probiert? Poste doch mal nen Snippet!

Mal so generell: Was schreibst Du da eigentlich? Soll das ne Art Editor für SQLite werden? Imho macht das Hinzufügen von Spalten nämlich in den wenigsten Fällen Sinn und ist eher Ausdruck für schlechtes DB-Design ...
Zuletzt geändert von Hyperion am Montag 8. Juni 2009, 19:29, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dann zeigt doch mal etwas Code und beschreibe dein Problem. Sonst wird sicher niemand helfen können. ;-)
Das Leben ist wie ein Tennisball.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Hyperion hat geschrieben:Mal so generell: Was schreibst Du da eigentlich? Soll das ne Art Editor für SQLite werden? Imho macht das Hinzufügen von Spalten nämlich in den wenigsten Fällen Sinn und ist eher Ausdruck für schlechtes DB-Design ...
Nein bei weitem nicht. Ich schreibe ein Interface zu einem anderen Programm. Die Parameter der Schnittstelle sollen zusätzlich in einer Datenbank abgelegt werden. Ich dachte es ist sichere ich prüfe zunächst ob die Spalte da ist, bevor ich versuche da was reinzuschreiben.
Die Parameter habe ich in Python-DIctionaries abgelegt und möchte Sie nun in einer sqlite-DB sichern. Bisher sieht das ganze etwa so aus:

Code: Alles auswählen

    def createtable(self, tablename, columns):
        __sql = "SELECT name FROM sqlite_master WHERE (type = 'table') and (name = '" + tablename + "')"
	    self.__cursor.execute(__sql)
        __row = self.__cursor.fetchone()
        
	if not __row:
            # Die Tabelle existiert noch nicht. Sie kann erstellt werden.
	    __sql = """CREATE TABLE %s (%s)""" % (tablename, ", ".join(columns))
	    self.__cursor.execute(__sql)

        # Alle existierenden Spaltennamen abfragen und in einer Liste sichern
        __sql = """SELECT name FROM sqlite_master WHERE (type = 'index')"""
        self.__cursor.execute(__sql)
        __spalten = self.__cursor.fetchall()        
       
        # Abgleich der Spalten (wenn nicht bereits vorhanden...)
        for __i in columns:
	    if not __i.split()[0] in __spalten:
	        print  __i.split()[0], type(__spalten[0])
                print "Spalte " + __i.split()[0] + " ist nicht in der Tabelle " + tablename + " vorhanden."
		__sql = "CREATE INDEX " + __i.split()[0] + " ON " + tablename + " (" + __i.split()[0] + ")"
		self.__cursor.execute(__sql)
Das anlegen einer Tabelle funktioniert einwandfrei. Probleme gibt es wenn die Tabelle samt der Spalten schon da ist. Ich schaffe es nicht das Tupel mit dem String aus meiner Liste zu vergleichen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Autsch, meine Augen tun vor lauter ``__`` weh, was hast du dir denn dabei gedacht?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Das ganze steht innerhalb einer Klasse und die Attribute sind privat... - Oder habe ich da etwas falsch verstanden?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Python hat keine privaten Attribute und ``__`` steht ganz sicher nicht für "privat". Wer hat dir denn sowas erzählt?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BastiL hat geschrieben: Nein bei weitem nicht. Ich schreibe ein Interface zu einem anderen Programm. Die Parameter der Schnittstelle sollen zusätzlich in einer Datenbank abgelegt werden. Ich dachte es ist sichere ich prüfe zunächst ob die Spalte da ist, bevor ich versuche da was reinzuschreiben.
Das kapiere ich leider so immer noch nicht. Nutzt das andere Programm eine DB zum Ablegen / Auslesen der Daten? Wenn ja, dann ist die doch vorhanden und man kann davon ausgehen, dass das so ok ist!

Ich würde ja bei insert-Statements einfach dei Felder explizit angeben, in die man Werte schreiben möchte. Sollte ein Feld nicht vorhanden sein, sollte es zu einer Exception kommen, die man dann gut abfangen kann. Imho ist das ein sauberer und einfacher Weg - zumal Du bei Deinem Ansatz nicht einmal garantieren kannst, dass zwischenzeitlich niemand anders die Tabellenstruktur ändert (Stichwort Transaktion).
BlackJack

Insbesondere wäre ein "privat" bei *lokalen* Namen auch ziemlich eigenartig.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Leonidas hat geschrieben:Python hat keine privaten Attribute und ``__`` steht ganz sicher nicht für "privat". Wer hat dir denn sowas erzählt?
http://openbook.galileocomputing.de/pyt ... 9c385b9ec3

Vielleicht verstehe ich das auch falsch?
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Hyperion hat geschrieben:Das kapiere ich leider so immer noch nicht. Nutzt das andere Programm eine DB zum Ablegen / Auslesen der Daten? Wenn ja, dann ist die doch vorhanden und man kann davon ausgehen, dass das so ok ist!.
So ist es im wesentlichen gedacht. Das Programm soll aber die Datenbank selbst verwalten und bei Bedarf (einmal im Jahr) eine neue Datenbank samt der dann nötigen Tabellen erzeugen.
Hyperion hat geschrieben: Ich würde ja bei insert-Statements einfach dei Felder explizit angeben, in die man Werte schreiben möchte. Sollte ein Feld nicht vorhanden sein, sollte es zu einer Exception kommen, die man dann gut abfangen kann. Imho ist das ein sauberer und einfacher Weg - zumal Du bei Deinem Ansatz nicht einmal garantieren kannst, dass zwischenzeitlich niemand anders die Tabellenstruktur ändert (Stichwort Transaktion).
Hmm also einfach die Abfrage weglassen und die exception abfangen?
Antworten