SQLite更新问题:executemany覆写所有行及循环更新报错
SQLite批量更新问题的原因与解决
此前问题
使用executemany更新SQLite的breakdown表characters列时,所有行都被写入列表最后一项的值,代码及结果如下:
执行代码:
c.executemany('UPDATE breakdown SET characters = ?', generator_list)
generator_list构造过程:
updated_local_sc_char_lists = ['1-HARPER, RORY, THOMAS', 'AUGUST, THOMAS'] generator_expression = ((val,) for val in updated_local_sc_char_lists) generator_list = list(generator_expression) # 最终generator_list为:[('1-HARPER, RORY, THOMAS',), ('AUGUST, THOMAS',)]
更新后查询结果:
[('AUGUST, THOMAS',), ('AUGUST, THOMAS',)]
更新问题
想要实现列表第一项更新第一行,第二项更新第二行(列表项数与行数一致),但编写如下代码后报错sqlite3.OperationalError: no such column: sc_id:
sc_id = 1 for x in generator_list: c.execute('UPDATE breakdown SET characters = ? WHERE rowid = sc_id', x) sc_id += 1
问题分析与解决
1. 原executemany失效的原因
你的UPDATE语句没有添加WHERE过滤条件,SQLite会把表中所有行的characters列更新为当前传入的参数值。executemany会循环执行这条语句,最后一次执行时,所有行都会被覆盖成列表的最后一项,最终结果全是同一个值。
2. 更新代码报错的原因
SQL语句中的sc_id被解析成了列名,而非你定义的变量值。SQLite找不到名为sc_id的列,因此抛出错误。
3. 正确实现方案
方案一:用executemany批量更新(推荐,效率更高)
将rowid(或自定义主键)与对应更新值组合成参数列表,一次性批量执行:
# 构造参数:(要更新的值, 对应的rowid) params = [(val, idx + 1) for idx, val in enumerate(updated_local_sc_char_lists)] # 执行批量更新,通过rowid匹配行 c.executemany('UPDATE breakdown SET characters = ? WHERE rowid = ?', params) # 提交事务,确保更新生效 conn.commit()
方案二:修复循环单条更新的代码
把sc_id作为参数传入SQL语句,用?占位符代替直接写变量名:
sc_id = 1 for val_tuple in generator_list: # 将sc_id加入参数元组,SQL中用?占位 c.execute('UPDATE breakdown SET characters = ? WHERE rowid = ?', (*val_tuple, sc_id)) sc_id += 1 # 提交事务 conn.commit()
额外说明
- 如果你的表有自定义主键(比如
id列),可以用自定义主键代替rowid来匹配行,逻辑完全一致。 - 所有数据库写操作后必须调用
conn.commit()提交事务,否则更新不会被持久化到数据库。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

