You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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解析失败。

修复步骤

  1. 修改createRowStatement,让它返回两个独立部分:纯SQL语句字符串,以及对应参数值的列表。
  2. 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:25:54