Python逐行将pandas数据去重插入SQLite3未生效问题排查
SQLite逐行插入contractors表无数据问题排查与修复
项目场景
- 运行环境:Windows 10 专业版、PyCharm 2020.3、Python 3.8
- 业务目标:基于SQLite3完成多sheet Excel数据入库,包含两张关联表:
contractors:存储去重后的唯一厂商名称,自增主键,GLOBAL_VENDOR_NAME字段配置唯一约束actions:存储各部门对应厂商的行为数、合同金额数据,通过外键关联contractors的主键ID
- 已完成流程:数据库建表、Excel多sheet遍历逻辑,当前卡点:逐行插入contractors表时无任何数据写入,因需要逐行校验厂商名称去重,无法使用批量插入方案。
现有代码的核心问题
- Cursor对象引用错误:
insert_data函数中创建cursor时,硬编码使用了全局变量conn,而非函数传入的数据库连接参数con。如果全局conn未完成初始化,cursor对象会直接触发未定义错误,后续的execute调用根本无法执行。 - SQL参数传递格式不兼容:SQLite驱动要求
execute方法的第二个参数必须是包含绑定值的元组/列表,哪怕只有一个参数也要写成(值,)的格式。原代码直接把厂商名字符串作为参数传入,驱动会把字符串拆成单个字符作为多组参数传入,和SQL里的单个占位符?数量不匹配,触发执行错误。 - 异常被完全静默吞没:代码中使用无指定捕获类型的
except: pass,会把所有运行错误(包括cursor未定义、参数不匹配、唯一约束冲突等)全部静默忽略,没有任何错误日志输出,表现就是代码跑完但数据库里没有任何数据写入。 - 冗余参数设计:
build_db函数接收了actions表的插入SQL参数sql2,但实际函数逻辑完全没有使用该参数,属于冗余设计,不影响当前运行但容易造成后续维护混乱。
修正后的可运行代码
import sqlite3 from sqlite3 import Error def get_sheet(file, sheet_name): # 保留原有读取Excel sheet的逻辑 pass def build_db(con, cont, names, sql_contract, sql_action): for sheet_name in names: try: temp = get_sheet(cont, sheet_name) # 调用contractors表的逐行插入逻辑 insert_contract_data(con, sql_contract, temp) except Error as e: print(f"处理sheet {sheet_name} 失败: {str(e)}") return def insert_contract_data(con, sql_cmd, sheet): # 校验数据库连接有效性 if con is None: print("数据库连接为空,无法执行插入操作") return # 使用传入的数据库连接创建cursor,不硬编码全局变量 c = con.cursor() for k, row in sheet.iterrows(): # 提取厂商名称并去除首尾空格 vendor_name = str(row[0]).strip() try: # 单参数必须封装为元组,适配SQLite驱动要求 c.execute(sql_cmd, (vendor_name,)) con.commit() except Error as e: # 打印具体错误,不静默吞掉异常 print(f"插入厂商 {vendor_name} 失败: {str(e)}") continue # 定义插入SQL insert_cont = """INSERT INTO contractors (GLOBAL_VENDOR_NAME) VALUES (?);""" insert_act = """INSERT INTO actions (DEPARTMENT, ACTIONS, DOLLARS, CONTRACTOR_ID) VALUES (?, ?, ?, ?);""" # 前置完成数据库连接、Excel文件读取、sheet名称列表获取后,执行调用 # build_db(conn, contract_file, sheet_names, insert_cont, insert_act)
实现说明
- 因为
GLOBAL_VENDOR_NAME本身配置了唯一约束,逐行插入时遇到重复厂商名称会自动抛出唯一约束冲突,直接捕获该异常跳过重复插入即可,不需要额外写先查询再判断的去重逻辑,完全符合逐行校验去重的要求。 - 后续处理actions表时,可通过
SELECT ID FROM contractors WHERE GLOBAL_VENDOR_NAME = ?的查询获取对应厂商的主键ID,结合当前遍历的sheet名称、行为数、金额字段完成关联入库。
内容的提问来源于stack exchange,提问作者Jacob L.
相关产品推荐
相关产品推荐

