【问题标题】:Having trouble updating database table with strings sqlite3使用字符串 sqlite3 更新数据库表时遇到问题
【发布时间】:2018-05-26 14:14:46
【问题描述】:

我在使用 python、sqlite3 时遇到问题,我可以用数字(整数或十进制)而不是字符串更新表。 link to a screenshot of program running here

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 更新为数字时,它工作得很好,但是当我尝试更新为字符串时,它会给出错误消息:

Traceback(最近一次调用最后一次): 文件“C:/Users/12smi/Documents/school/computing/SQL/database with add and remove function.py”,第 99 行,在 修正记录() 文件“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'是我当时输入的字符串)

我不知道为什么会这样,所以任何帮助都会很棒:)

【问题讨论】:

  • 我真的无法跟上查询字符串格式的斗争。请不要使用它,这是一个很大的 SQL 注入风险,它会导致代码变慢且不清晰。至于你的错误,我们看不到表,所以大概Adventure 不存在于架构中
  • "UPDATE tblGames SET {} = ? WHERE game = ?".format(field), (newfield, newVal))。但是由于用户输入,这确实很容易出错并且仍然不安全。

标签: python sqlite


【解决方案1】:

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

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

当你可能打算执行时

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

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

cmets 已经指出您的代码中有一个更大的问题。您正在使用未经处理的字符串将查询拼接在一起,这是一种反模式。 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 成为多选输入而不是文本输入。这样您就可以更加确定它是安全的,并且您必须少对数据库进行一次查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多