我有一个我自己取乐的个人数据库(因此,与我自己创建的私有数据库一样,它与sql注入无关),并且正在尝试更改使用字符串格式(.format())创建的函数和占位符(?,%s等),并改用f字符串。我遇到了一个问题,因为我将sqlite3查询更改为f字符串,现在无法运行将指定列更新为指定行的函数之一。
这是我当前使用f字符串的函数:
import sqlite3
from tabulate import tabulate
conn = sqlite3.connect("Table.db")
c = conn.cursor()
def updatedb(Column, Info, IdNum):
with conn:
data = c.execute(f"UPDATE Table_name SET {Column} = {Info} WHERE IdNum={IdNum}")
c.execute(f"SELECT * FROM Table_name WHERE IdNum = {IdNum}")
print(tabulate(data, headers="keys", tablefmt="grid", stralign='center', numalign='center'))
该函数通过用所需的新信息更新指定行中的指定列来更新该表。例如,在3 x 3表中,如果该列是年龄或其他内容,则可以使用该函数将第1行,第2列更新为18,而不是第1列,第2列为17。之后的选择查询将仅选择已更新的特定行,然后使用列表表包打印出打印语句,以打印出整洁有序的表。
每当我尝试使用此功能时遇到的错误是:
sqlite3.OperationalError: no such column: Info
无论我在函数中为Info变量键入什么内容,都会导致错误,但我不知道如何解决该问题。
这是我在尝试更改为f字符串之前拥有的更新语句,它对我来说很好:
data = c.execute("UPDATE Table_name SET {} = ? WHERE IdNum=?".format(Column), (Info, IdNum))
将上面的查询更改为f字符串似乎没什么大变化,但是它不起作用,因此希望得到任何反馈。
答案 0 :(得分:2)
这里的问题是理解参数化-它仅适用于参数,不适用于列名和其他内容。
在此示例中:
query = 'SELECT * FROM foo WHERE bar = ? AND baz = ?'
params = (a, b)
cursor.execute(query, params)
请注意,查询和数据分别传递到.execute
-数据库的工作是进行插值-使您摆脱引号地狱,并使程序更安全禁用任何一种SQL注入。它的性能也可能更好-它允许数据库缓存已编译的查询,并在您更改参数时使用它。
现在仅适用于数据。如果要在变量中使用实际的列名,则必须在查询中自己插入它:
col1 = 'bar'
col2 = 'baz'
query = f'SELECT * FROM foo WHERE {col1} = ? AND {col2} = ?'
cursor.execute(query, params)
答案 1 :(得分:0)
参数化和字符串替换是两件事。
最基本的问题是,字符串替换会产生以下形式的命令:
. . . SET some_column = some_info . . .
SQL需要
. . . SET some_column = 'some_info' . . .
(即,用引号引起来的字符串值)。 SQLite会将未引用的字符串解释为由列名组成的表达式。
您不能通过简单地在格式字符串中添加单引号来解决此问题,您可能会相信。如果替换值本身包含单引号会发生什么?这种方式既可以避免转义字符串,也可以避免SQL注入的危险。
相反,只需使用参数化即可。
但是,请注意,您不能参数化列名({Column}
),在防止注入发生的同时,必须使用字符串替换。< / p>
答案 2 :(得分:0)
要改进nosklo关于f-strings的使用的上述答案,您只需要在变量周围使用转义引号即可将它们作为字符串发送给SQLite:
import sqlite3
conn = sqlite3.connect("somedatabase.db")
c = conn.cursor()
def updatedb(colname, colvalue, rowid):
with conn:
c.execute(f"UPDATE tablename SET \"{colname}\" = \"{colvalue}\" WHERE rowidentifier = \"{rowid}\"")
出于安全原因,请勿将字符串插值与依赖外部用户输入的数据库一起使用。但是,如果您清理输入字符串,我想您可以使它工作。
答案 3 :(得分:-2)
您尝试过
data = c.execute(f"UPDATE Table_name SET \'{Column}\' =\'{Info}\')
?