执行SQLite更新操作时出现‘no such column’错误的原因排查
问题:SQLite执行UPDATE语句时出现"no such column: foo"错误
我尝试将数据库中的字符串替换为ID,编写了如下Python代码:
import sqlite3 TABLES = ['table1', 'table2', ...] PAR_TYPES_STRINGS = ['foo', 'bar', ...] PAR_TYPES_ID = [1, 2, ...] def upateTable(table, parTypeId, parTypeString): return f"UPDATE {table} SET par_type = {parTypeId} WHERE par_type = {parTypeString};" conn = sqlite3.connect('existing_db.db') cursor = conn.cursor() for table in TABLES: for index, parTypeString in enumerate(PAR_TYPES_STRINGS): parTypeId = PAR_TYPES_ID[index] cursor.execute(upateTable(table, parTypeId, parTypeString)) conn.commit() cursor.close()
运行后返回错误:
sqlite3.OperationalError: no such column: foo
明明是把par_type作为列名,和动态传入的parTypeString(值为foo)做比较,为什么会提示不存在foo列?
解答
这是因为你用f-string直接拼接SQL语句时,字符串值foo没有被加上引号,导致SQL解析器把它当成了列名,而非字符串值。比如生成的SQL语句是:
UPDATE table1 SET par_type = 1 WHERE par_type = foo;
这里的foo没有引号,SQL会认为它是一个列,自然会报“不存在该列”的错误。
正确的做法是使用SQLite的参数化查询,不要直接拼接字符串。参数化查询会自动处理字符串的引号包裹,同时能避免SQL注入风险。修改后的代码如下:
import sqlite3 TABLES = ['table1', 'table2', ...] PAR_TYPES_STRINGS = ['foo', 'bar', ...] PAR_TYPES_ID = [1, 2, ...] conn = sqlite3.connect('existing_db.db') cursor = conn.cursor() for table in TABLES: # 表名无法用参数化,若TABLES是可信来源可直接拼接,否则需做合法性校验 update_sql = f"UPDATE {table} SET par_type = ? WHERE par_type = ?;" for par_type_id, par_type_str in zip(PAR_TYPES_ID, PAR_TYPES_STRINGS): cursor.execute(update_sql, (par_type_id, par_type_str)) conn.commit() cursor.close()
关键修改说明:
- 用
?作为参数占位符,在cursor.execute()的第二个参数中传入参数元组,SQLite会自动处理字符串的引号和转义 - 使用
zip()同时遍历ID和对应字符串,代码更简洁高效 - 彻底避免了直接拼接字符串值带来的语法错误和安全隐患
内容的提问来源于stack exchange,提问作者four-eyes
相关产品推荐
相关产品推荐

