如何编写引用动态列名的UPDATE SQL查询?
问题:动态列名的SQLite UPDATE查询无法正常执行
我写了个函数,遍历表的列名列表执行SELECT查询,然后逐条对比字段值和清洗后的值,不一样就执行UPDATE把清洗后的值写回去,但UPDATE一直报错。
有个功能类似的函数用下面的查询没问题:
dbcursor.execute('''UPDATE alib set live = (?) WHERE rowid = (?);''', (islive, row_to_process))
两者的区别是这个函数需要遍历列名。我知道字段名不能用参数绑定,所以动态构建了SELECT的查询字符串,这部分是正常的,但UPDATE就出问题了:
for text_tag in text_tags: dbcursor.execute('''CREATE INDEX IF NOT EXISTS dedupe_tag ON alib (?) WHERE (?) IS NOT NULL;''', (text_tag, text_tag)) print(f"- {text_tag}") ''' 获取匹配记录列表 ''' ''' 由于无法将变量作为字段名传入SELECT语句,需动态构建查询字符串后执行 ''' query = f"SELECT rowid, {text_tag} FROM alib WHERE {text_tag} IS NOT NULL;" dbcursor.execute(query) ''' 处理每条匹配记录 ''' records = dbcursor.fetchall() records_returned = len(records) > 0 if records_returned: for record in records: # <SNIP> 此处省略值清洗逻辑 if final_value != stored_value_sorted: ''' 将{final_value}写入rowid对应的{text_tag}列 ''' row_to_process = record[0] query = # 以下是尝试的三种写法 print(query) # 临时代码用于查看生成的查询 dbcursor.execute(query)
待写入的值可能包含\、'、"、[、]、(、)和各种标点,我试了三种写法都报错,第77行是dbcursor.execute(query):
写法1:
query = f"UPDATE alib SET {text_tag} = (?) WHERE rowid = (?);", (final_value, row_to_process)
报错信息:
('UPDATE alib SET artist = (?) WHERE rowid = (?);', ('8:58\\\\The Unthanks', 305091)) Traceback (most recent call last): File "<string>", line 80, in <module> File "<string>", line 77, in dedupe_fields TypeError: execute() argument 1 must be str, not tuple
写法2:
query = f"UPDATE alib SET {text_tag} = '{final_value}' WHERE rowid = {row_to_process};"
报错信息:
UPDATE alib SET recordinglocation = 'Ashwoods, Stockholm\\Electric Lady Studioss, Stockholm\\Emilie's, Stockholm\\Ingrid Studioss, Stockholm\\Judios Studioss, Stockholm\\Nichols Canyon Houses, Stockholm\\Ocean Way Studioss, Stockholm\\RAK Studios, London\\Studio De La Grande Armée, Paris\\The Villages, Stockholm\\Vox Studioss, Stockholm' WHERE rowid = 124082; Traceback (most recent call last): File "<string>", line 80, in <module> File "<string>", line 77, in dedupe_fields sqlite3.OperationalError: near "s": syntax error
写法3:
query = f"UPDATE alib SET {text_tag} = {final_value} WHERE rowid = {row_to_process};"
报错信息:
UPDATE alib SET artist = 8:58\\The Unthanks WHERE rowid = 305091; Traceback (most recent call last): File "<string>", line 80, in <module> File "<string>", line 77, in dedupe_fields sqlite3.OperationalError: near ":58": syntax error
解决方法
核心问题是对SQL参数绑定的用法理解偏差:字段名确实无法用参数绑定,必须动态拼接,但字段值必须通过参数传递,才能避免语法错误和SQL注入风险。
正确写法如下:
# 动态拼接带占位符的SQL字符串(字段名用f-string拼接) query = f"UPDATE alib SET {text_tag} = ? WHERE rowid = ?;" # 将值和rowid作为第二个参数传给execute dbcursor.execute(query, (final_value, row_to_process))
三种错误写法的原因:
- 写法1:错误地把SQL字符串和参数打包成元组赋值给
query,但execute要求第一个参数是纯SQL字符串,第二个参数才是参数元组,两者不能混合。 - 写法2:直接把值拼进SQL字符串,当值包含单引号时,会打断SQL语句的字符串闭合逻辑,导致语法错误(比如
Emilie's中的单引号)。 - 写法3:值未加引号包裹,SQL会把
8:58\\The Unthanks识别为语法片段而非字符串值,自然触发语法错误。
额外提醒:动态拼接字段名时,最好校验列名是否在预设的合法列表中,避免SQL注入风险。
内容的提问来源于stack exchange,提问作者evand
相关产品推荐
相关产品推荐

