SQLite删除数据后如何重新索引并更新自增主键ID?
解决SQLite删除数据后主键ID递补问题
首先明确:SQLite的INTEGER PRIMARY KEY AUTOINCREMENT设计初衷是生成唯一不重复的ID,不建议频繁修改主键——如果有其他表关联该主键作为外键,修改会直接导致关联失效。但如果你的场景确实需要让ID连续递补,可以按以下两种方案实现:
方案1:删除后重新编号主键并重置序列
删除指定数据后,执行两个关键操作:更新后续数据的acc_id使其依次递补,再重置SQLite的自增序列避免新插入数据时ID冲突。
修改你的DeleteFromDatabase方法如下:
def DeleteFromDatabase(self): Value_No = 65536 Value_Yes = 16384 isconfirm = self.ask_for_delete() if isconfirm == Value_Yes: account_id = int(self.exm_acc_ui.aditaccLabel.text().split(": ")[-1]) target_id = account_id - 1 # 确认此处是待删除的正确ID conn6 = sqlite3.connect("AccStorage.db") c6 = conn6.cursor() # 1. 删除指定数据 c6.execute("DELETE FROM acc_storage WHERE acc_id = ?", (target_id,)) # 2. 更新后续数据的acc_id,实现递补 c6.execute("UPDATE acc_storage SET acc_id = acc_id - 1 WHERE acc_id > ?", (target_id,)) # 3. 重置自增序列,让下一次插入从当前最大ID+1开始 c6.execute(""" UPDATE sqlite_sequence SET seq = COALESCE((SELECT MAX(acc_id) FROM acc_storage), 0) WHERE name = 'acc_storage' """) conn6.commit() conn6.close() self.editaccWindow.close() self.examineAccWindow.close() self.acc_info_read() elif isconfirm == Value_No: pass
注意点:
- 用参数化查询(
?占位符)替代字符串拼接,避免SQL注入风险 - 如果数据库存在关联外键的表,绝对不能使用此方案
方案2:界面行号不依赖主键ID(更推荐)
如果只是为了解决界面行号和ID不匹配导致的崩溃,无需修改主键,只需在查询数据时生成独立的行号用于界面关联:
在acc_info_read()方法中查询数据时,用ROW_NUMBER()生成界面行号,实际操作仍用acc_id:
def acc_info_read(self): conn = sqlite3.connect("AccStorage.db") c = conn.cursor() # 生成带界面行号的结果集 c.execute(""" SELECT ROW_NUMBER() OVER (ORDER BY acc_id) as row_num, * FROM acc_storage ORDER BY acc_id """) data = c.fetchall() conn.close() # 填充表格时,用row_num对应QTableWidget的行号,同时记录每行对应的acc_id # 删除时直接取对应行的acc_id即可,无需再计算行号与ID的关系
这种方式避免了主键修改带来的潜在风险,同时彻底解决行号与ID不匹配的问题。
内容的提问来源于stack exchange,提问作者Tasarruflu Fare
相关产品推荐
相关产品推荐

