首页 > 解决方案 > 使用字符串 sqlite3 更新数据库表时遇到问题

问题描述

python, sqlite3 有问题,我可以用数字(整数或十进制)而不是字符串更新表。 链接到此处运行的程序的屏幕截图

def amendRec():    #FIX ME PLEASE
edit="yes"
while edit !='exit':
    keyfield=input("enter the game name of the record you want to edit. ")
    keyfield="'"+keyfield+"'"
    field=input("enter the field you want to change. ")

    newVal=input("enter the new data for this field. ")
    #try:
    cursor.execute("UPDATE tblGames SET " + field + "=" + newVal +  " WHERE game = " + keyfield)
    conn.commit()
    print("\nRecord Updated\n")
    #except:
        #print("invalid game name or field entered.")
    edit=input("type 'exit' to stop editing, or press enter to continue. \n")
    showtable()

except 语句被注释掉,所以我可以看到 try 语句的错误消息。同样,当我尝试将 enrty 更新为数字时,它可以完美运行,但是当我尝试更新为字符串时,它会给出错误消息:

回溯(最后一次调用):文件“C:/Users/12smi/Documents/school/computing/SQL/database with add and remove function.py”,第 99 行,在 amendRec() 文件“C:/Users/12smi /Documents/school/computing/SQL/database with add and remove function.py”,第 82 行,在 amendRec cursor.execute("UPDATE tblGames SET" + field + "=" + newVal +" WHERE game = " + keyfield) sqlite3.OperationalError:没有这样的列:冒险

('Adventure'是我当时输入的字符串)

我不知道为什么会发生这种情况,所以任何帮助都会很棒:)

标签: pythonsqlite

解决方案


您收到该错误是因为您尝试执行

UPDATE tblGames SET genre=Adventure WHERE game = 'Shadow of the Colossus';

而你可能打算执行

UPDATE tblGames SET genre='Adventure' WHERE game = 'Shadow of the Colossus';

如果您只是去进行更改,它将起作用,但是我会与您生气,因为您的代码很危险

注释已经指出,您的代码中有一个更大的问题。您正在使用未经处理的字符串将查询拼接在一起,这是一种反模式。Python 的 sqlite3 库允许您将参数绑定到查询。您查询中的任何?内容都将替换为您选择的值(下面的示例)。

不过,你还有另一个问题。您不能将列名绑定为参数。尝试这样做会'columnName'在查询中而不是columnName. 没有安全的方法可以做到这一点,因为它是另一种反模式。但是既然我们在这里,至少让我们以一种安全的方式来做吧。我们将不得不将列名嵌入到查询中,但我们不能只嵌入任何用户输入,因为担心 SQL 注入。因此,我们必须确保我们嵌入的字符串是一个列名,并且只是一个列名。换句话说,我们将不得不清理输入。

下面的代码将清理列名,以便只有有效的列名才能进入查询。它还使用 sqlite3 的功能嵌入其他参数,为您清理输入。

def amendRec():
    edit = "yes"
    while edit != 'exit':
        keyfield = input("enter the game name of the record you want to edit. ")
        field = input("enter the field you want to change. ")

        # Check whether the specified colmun exists or not.
        # Any SQL injection will fail this test.
        query = "PRAGMA table_info ('tblGames');"
        columnExists = False
        for columnName in map(lambda x: x[1], cur.execute(query)):
            if columnName == field:
                columnExists = True

        if columnExists:
            # field can only be one of the column names since it's sanitized above.
            query = "UPDATE tblGames SET {} = ? WHERE game = ? ;".format(field)
            new_val = input("enter the new data for this field. ")
            # We pass in a tuple containing our desired parameters as the second parameter of cursor.execute.
            # new_val will replace the first ? and keyfield will replace the second ?.
            cursor.execute(query, (new_val, keyfield))
            conn.commit()
            print("\nRecord Updated\n")
        else:
            print("Sorry, that column doesn't exist.")

        edit = input("type 'exit' to stop editing, or press enter to continue. \n")
        showtable()

理想情况下,您field应该是多选输入而不是文本输入。这样您就可以更加确定它是安全的,并且您必须少对数据库进行一次查询。


推荐阅读