2016-07-24 9 views
0

Ich schreibe einige Scoring-Server mit Python und SQLite, und Fehler bei der Verwendung von Update aufgetreten.Python SQLite Update Fehler

Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from server import * 
>>> db = DB_control() 
>>> db.update_user_score("ZSPEF1", "FXVCWI", 180) 
UPDATE score SET FXVCWI = 180 WHERE USER_ID = ZSPEF1 
Error raised while updating ID ZSPEF1's score to 180. Rolling back DB... 
DB Successfully rolled back 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "server.py", line 102, in update_user_score 
    musica_db.execute(update_score_str) 
sqlite3.OperationalError: no such column: ZSPEF1 
>>> 

Score-Tabelle sieht wie folgt aus: score table screenshot

Wie Sie sehen, gibt es FXVCWI Spalte und Zeile ZSPEF1 und wollen diesen Wert ändern, aber Fehler sagt, es gibt keine ZSPEF1 Spalte.
UPDATE-Befehl tritt nur Fehler bei update_user_score-Funktion.

Warum passiert mir das? Es tritt auch manchmal ein Fehler auf, wenn das erste Zeichen in der Zeichenfolge die Nummer ist. Gibt es eine Möglichkeit, diesen Fehler zu vermeiden?

Hier ist mein Code

#!/usr/bin/env python 
import sqlite3 

musica_db_file = sqlite3.connect("musica.db") 
musica_db = musica_db_file.cursor() 

class DB_control(object): 
    def setupDB(self): 
     #This function should execute only on first run. 
     try: 
      userDB_setupDB_str = "NUM   INTEGER PRIMARY KEY AUTOINCREMENT, " 
      userDB_setupDB_str += "CARD_ID  TEXT NOT NULL UNIQUE, " 
      userDB_setupDB_str += "NAME  TEXT NOT NULL UNIQUE, " 
      userDB_setupDB_str += "PASSWORD TEXT NOT NULL, " 
      userDB_setupDB_str += "ADMIN  INT NOT NULL DEFAULT 0" 

      songDB_setupDB_str = "NUM   INTEGER PRIMARY KEY AUTOINCREMENT, " 
      songDB_setupDB_str += "SONG_ID  INT NOT NULL UNIQUE, " 
      songDB_setupDB_str += "NAME  TEXT NOT NULL UNIQUE, " 
      songDB_setupDB_str += "FINGERPRINT TEXT NOT NULL UNIQUE" 

      scoreDB_setupDB_str = "USER_ID  TEXT NOT NULL UNIQUE" 

      musica_db.execute('CREATE TABLE user({0}) '.format(userDB_setupDB_str)) 
      musica_db.execute('CREATE TABLE song({0}) '.format(songDB_setupDB_str)) 
      musica_db.execute('CREATE TABLE score({0})'.format(scoreDB_setupDB_str)) 
      musica_db_file.commit() 

      self.add_user(randomID(), 'MU_Admin', 'yj809042', admin=True) #Create admin account. 
      self.add_song(randomID(), 'Tutorial', randomID()) #Create tutorial(dummy) song 
      print("DB setuped.") 
     except: 
      print("Error raised while setuping DB") 
      raise 
    def update_user_score(self, cardID, songID, score): 
     try: 
      update_score_str = "UPDATE score SET {0} = {1} WHERE USER_ID = {2}".format(songID, score, cardID) 
      print update_score_str 
      musica_db.execute(update_score_str) 
      musica_db_file.commit() 
      print("User ID {0}'s score is now {1}.".format(cardID, score)) 
     except: 
      print("Error raised while updating ID {0}'s score to {1}. Rolling back DB...".format(cardID, score)) 
      self.rollback_DB() 
      raise 
    def rollback_DB(self): 
     try: 
      musica_db_file.rollback() 
      musica_db_file.commit() 
      print("DB Successfully rolled back") 
     except: 
      print("Error raised while rolling back DB. Critical.") 
      raise 
+0

Ich glaube, Sie brauchen Anführungszeichen um user_id – fodma1

+0

@ fodma1 Das hat nicht für mich funktioniert. "UPDATE Punktzahl SET {0} = {1} WHERE 'USER_ID' = {2}". Format (SongID, Score, KartenID) –

+0

@ LeeM.U. nicht so. Ich meine die tatsächliche ID "UPDATE score SET {0} = {1} WHERE USER_ID = '{2}'" ' – fodma1

Antwort

1

Sie Interpolations-Spaltenwerte als SQL Objektnamen, ohne zu zitieren:

update_score_str = "UPDATE score SET {0} = {1} WHERE USER_ID = {2}".format(songID, score, cardID) 
musica_db.execute(update_score_str) 

Verwenden Sie String-Interpolation nicht für SQL Werte. Verwenden Sie binden Parameter statt:

update_score_str = "UPDATE score SET {0} = ? WHERE USER_ID = ?".format(songID) 
musica_db.execute(update_score_str, (score, cardID)) 

Die cursor.execute() Funktion wird dann kümmern sich um die richtige zu zitieren, reduziert das Risiko von SQL-Injection.

Sogar interpolierende SQL-Objektnamen (songID hier) ist zwielichtig; Stellen Sie sicher, dass Sie diese Zeichenfolge im Voraus validieren.

Es sieht so aus, als ob Sie eine Spalte pro Song erstellen. Sie möchten wahrscheinlich mehr über das korrekte Design relationaler Tabellen lesen und nicht speichern Sie Daten in Spaltennamen. Verwenden Sie stattdessen eine number-to-many-Tabelle user_song_scores, in der die Tabelle (USER_ID, SONG_ID, SCORE) Tupel speichert und Sie die Ergebnisse für einen bestimmten Song stattdessen mit UPDATE user_song_scores SET score=? WHERE USER_ID=? AND SONG_ID=? aktualisieren können. Dadurch entfällt die Notwendigkeit, Spaltennamen zu generieren.

+0

Danke! Das hat für mich funktioniert. Ich bin neu in der DB, also wusste ich nicht über viele-zu-viele-Tische. Vielleicht sollte ich meinen Code neu schreiben;) –