使用CS50 SQL对象向SQLite插入动态列数据时执行报错求助
CS50期末项目:动态SQL插入语句错误排查
问题背景
我正在开发CS50在线编程课程的期末项目——一个基于Python、SQLite、Flask的教师即时评分系统。功能流程是:教师登录后选择学生团队,查看学生图片并提交评分,数据以CSV作为输入输出。由于CS50提供的SQL对象不支持pandas.to_sql,我只能手动遍历CSV行插入数据。因为每次评分会生成动态列(如attendence_lab_1),需要从CSV读取表头生成动态INSERT语句。目前表创建成功,但插入数据时出现**“语句需用换行或分号分隔”“字符串字面量未终止”**错误。
相关代码
# https://pandas.pydata.org/docs/reference/io.html df = pd.read_csv(stpath, header=0) #df.to_sql(students, con) headers = df.columns.values.tolist() # 从DataFrame获取表头列表 # 创建表的动态语句 def createTableStatement(tableName, columnList): return f"CREATE TABLE IF NOT EXISTS {tableName} (id INTEGER, {columnList[0]}" + (", {}"*(len(columnList)-1)).format(*(columnList[1:])) + ", PRIMARY KEY(id))" db.execute(createTableStatement("students", headers)) # 生成插入行的动态语句 def createRowStatement(columnList): return f'"INSERT INTO students ({columnList[0]}' + (', {}'*(len(columnList)-1)).format(*(columnList[1:])) + ') VALUES (?' + (', ?'*(len(columnList)-1)) + ')", row["Student"]' + (', row["{}"]'*(len(columnList)-1)).format(*(columnList[1:])) + ')' with open(stpath, "r", encoding='utf-8-sig') as file: reader = csv.DictReader(file) for row in reader: x = createRowStatement(headers) print(x) db.execute(x)
生成的错误语句示例
"INSERT INTO students (Student, Team, Session, Pod, Image, Lab1_Grade, Lab1_attend, Lab1_prep, Lab1_part, Lab1_disect) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", row["Student"], row["Team"], row["Session"], row["Pod"], row["Image"], row["Lab1_Grade"], row["Lab1_attend"], row["Lab1_prep"], row["Lab1_part"], row["Lab1_disect"])
错误原因及解决方案
核心错误
createRowStatement函数错误地将SQL语句字符串和Python参数变量拼接成了一个混合字符串,而CS50的db.execute方法要求第一个参数是纯SQL语句,后续参数是独立的参数值(不能把row["Student"]这种Python代码写进SQL字符串里)。生成的语句还包含多余的双引号和末尾括号,导致SQL解析失败。
修复步骤
- 修改
createRowStatement,让它返回两个独立部分:纯SQL语句字符串,以及对应参数值的列表。 - 调用
db.execute时,分别传入SQL语句和参数列表。
修改后的代码如下:
# 生成插入行的动态语句(修复版) def createRowStatement(columnList, row): # 拼接列名和占位符 cols = ', '.join(columnList) placeholders = ', '.join(['?'] * len(columnList)) sql = f"INSERT INTO students ({cols}) VALUES ({placeholders})" # 从当前row中提取对应列的参数值 params = [row[col] for col in columnList] return sql, params with open(stpath, "r", encoding='utf-8-sig') as file: reader = csv.DictReader(file) for row in reader: sql, params = createRowStatement(headers, row) print(sql) print(params) db.execute(sql, params)
额外优化建议
- 原
createTableStatement没有指定列的数据类型,虽然SQLite支持无类型列,但为了规范,可以给每个列加上TEXT类型(或根据实际数据类型调整):def createTableStatement(tableName, columnList): cols_with_types = ', '.join([f"{col} TEXT" for col in columnList]) return f"CREATE TABLE IF NOT EXISTS {tableName} (id INTEGER, {cols_with_types}, PRIMARY KEY(id))"
内容的提问来源于stack exchange,提问作者Badger273
相关产品推荐
相关产品推荐

