sqlite ich sehe den Fehler nicht...

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Hallo!
Zu Übungszwecken versuche ich mich an einer Musik-Datenbank:

Code: Alles auswählen

import sqlite3

def create_db_tables(db_conn, tables):
    db_conn.execute("""CREATE TABLE IF NOT EXISTS {0} (
                           id INTEGER PRIMARY KEY,
                           name TEXT UNIQUE,
                           sort_name TEXT DEFAULT '',
                           musicbrainz_url TEXT DEFAULT '' )""".format(tables["artist"]))
    
    db_conn.execute("""CREATE TABLE IF NOT EXISTS {0} (
                           id INTEGER PRIMARY KEY,
                           name TEXT UNIQUE,
                           sort_name TEXT DEFAULT '',
                           musicbrainz_url TEXT DEFAULT '' )""".format(tables["release"]))
    
    db_conn.execute("""CREATE TABLE IF NOT EXISTS {0} (
                           id INTEGER PRIMARY KEY,
                           name TEXT UNIQUE)""".format(tables["genre"]))
    
    db_conn.execute("""CREATE TABLE IF NOT EXISTS {0} (
                            id INTEGER PRIMARY KEY,
                            title TEXT UNIQUE,
                            musicbrainz_url TEXT DEFAULT '',
                            release INTEGER,
                            FOREIGN KEY(release) REFERENCES {1}(id),
                            artist INTEGER,
                            FOREIGN KEY(artist) REFERENCES {2}(id),
                            my_genre INTEGER,
                            FOREIGN KEY(my_genre) REFERENCES {3}(id) )""".format(tables["track"], tables["release"], tables["artist"], tables["genre"]))

project = "test"
tables = {  "artist": "artists",
            "track": "tracks",
            "release": "releases",
            "genre": "genres"}

db_connection = sqlite3.connect(project + ".db")
cur = db_connection.cursor()
create_db_tables(cur, tables)
es kommt folgende Fehlermeldung:

Code: Alles auswählen

  File "/home/werner/workspace_db.py", line 51, in <module>
    create_db_tables(cur, tables)
  File "/home/werner/workspace_db.py", line 35, in create_db_tables
    FOREIGN KEY(my_genre) REFERENCES {3}(id) )""".format(tables["track"], tables["release"], tables["artist"], tables["genre"]))
sqlite3.OperationalError: near "artist": syntax error
und ich sehe beim besten Willen nicht, woran's liegt :K

Habt ihr eine Idee?
Vielen Dank, Werner
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

PS: in d Zwischenzeit hab ich noch ein bisschen in der String-Formatierungs-Doku gestöbert:

Code: Alles auswählen


db_conn.execute("""CREATE TABLE IF NOT EXISTS {track} (
                            id INTEGER PRIMARY KEY,
                            title TEXT UNIQUE,
                            musicbrainz_url TEXT DEFAULT '',
                            release INTEGER,
                            FOREIGN KEY(release) REFERENCES {release}(id),
                            artist INTEGER,
                            FOREIGN KEY(artist) REFERENCES {artist}(id),
                            my_genre INTEGER,
                            FOREIGN KEY(my_genre) REFERENCES {genre}(id) )""".format(**tables))


ändert aber natürlich nichts an der Fehlermeldung...
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

...und nach noch weiteren Recherchen funktioniert nun:

Code: Alles auswählen

db_conn.execute("""CREATE TABLE IF NOT EXISTS {track} (
                            id INTEGER PRIMARY KEY,
                            title TEXT UNIQUE,
                            musicbrainz_url TEXT DEFAULT '',
                            release INTEGER,
                            artist INTEGER,
                            my_genre INTEGER,
                            FOREIGN KEY(artist) REFERENCES {artist}(id),
                            FOREIGN KEY(release) REFERENCES {release}(id),
                            FOREIGN KEY(my_genre) REFERENCES {genre}(id) )""".format(**tables))
FOREIGN KEY darf natürlich erst am Ende aufgerufen werden :oops:
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

.format(**tables)
SQLite will eigentkich nicht das du die Strings selber zusammenbaust und lieber selber die variablen escapen. Das willst du doch später für die Abfragen dann auch so machen oder? :-)

http://docs.python.org/library/sqlite3.html
Usually your SQL operations will need to use values from Python variables. You shouldn’t assemble your query using Python’s string operations because doing so is insecure; it makes your program vulnerable to an SQL injection attack (see http://xkcd.com/327/ for humorous example of what can go wrong).

Instead, use the DB-API’s parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor’s execute() method.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Sr4l:
Instead, use the DB-API’s parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor’s execute() method.
Ich wundere mich aber auch, warum die Tabellen mittels String Formatting erzeugt werden. Hier gibt es gar keinen Grund dazu. Auch würde ich mir überlegen mit SQLAlchemy zu arbeiten und nicht direkt mit den rohen Statements. Ist halt die Frage, was genau das Ziel der Übung ist.
Das Leben ist wie ein Tennisball.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Ich wundere mich aber auch, warum die Tabellen mittels String Formatting erzeugt werden. Hier gibt es gar keinen Grund dazu. [/quote]
Grund nicht, aber dafür ist es noch kein Sicherheitsrisiko.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Ja, die String-Formatierung ist "Overkill" - ich dachte, wenn ich die Namen in einem Dictionary speichere, kann ich sie einfacher ändern (bis das endgültige Datenbank-Layout steht) und auch nirgends falsch schreiben (Naja, so kriege ich einen key-error, wenn ich mich verschreibe, und anders einen sqlite-error, macht nicht viel Unterschied)
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

es wurde ja schon SQLAlchemy erwähnt. Wenn du da den [quote=http://docs.sqlalchemy.org/en/rel_0_7/o ... ative.html]Deklarativen Ansatz[/quote] wählst, kann du die Namen etc. auch ziemlich schnell ändern.

Gruß, noisefloor
Antworten