如何修改Python代码实现CSV导入关系数据库时避免插入重复条目
问题核心原因
- 建表未给
shows.title、genres.genre添加唯一约束,INSERT OR IGNORE仅在触发唯一键冲突时才会跳过插入,无约束场景下重复数据会正常写入 - shows表无去重插入逻辑,每读取一行CSV就直接插入,同名称影视会生成多条重复记录
- 多类型影视的关联表插入写在类型遍历循环外,仅会保存最后一个分类的映射关系
INSERT OR IGNORE跳过插入时,返回值不是对应已存在记录的ID,需额外查询获取正确主键
修正后完整代码
import csv from cs50 import SQL # 初始化数据库 open("shows.db", "w").close() db = SQL("sqlite:///shows.db") # 建表新增唯一约束,主键指定自增 db.execute(""" CREATE TABLE shows ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT UNIQUE NOT NULL ) """) db.execute(""" CREATE TABLE genres ( id INTEGER PRIMARY KEY AUTOINCREMENT, genre TEXT UNIQUE NOT NULL ) """) db.execute(""" CREATE TABLE shows_genres ( show_id INTEGER NOT NULL, genre_id INTEGER NOT NULL, FOREIGN KEY(show_id) REFERENCES shows(id), FOREIGN KEY(genre_id) REFERENCES genres(id), PRIMARY KEY(show_id, genre_id) ) """) # 可选:如果需要实现影视名称别名映射(比如Games of Thrones显示为GoT),可以加这个字典 title_alias = { "GAMES OF THRONES": "GoT" } with open("Favorite TV Shows - Form Responses 1.csv", "r") as file: reader = csv.DictReader(file) for row in reader: # 统一标题大小写 raw_title = row["title"].strip().upper() # 应用别名(不需要可以直接用raw_title插入) show_title = title_alias.get(raw_title, raw_title) # 插入或忽略影视,之后查询对应ID db.execute("INSERT OR IGNORE INTO shows (title) VALUES (?)", show_title) show_id = db.execute("SELECT id FROM shows WHERE title = ?", show_title)[0]["id"] # 遍历处理每个分类 for genre in row["genres"].split(", "): # 插入或忽略分类,之后查询对应ID db.execute("INSERT OR IGNORE INTO genres (genre) VALUES (?)", genre) genre_id = db.execute("SELECT id FROM genres WHERE genre = ?", genre)[0]["id"] # 插入关联关系,联合主键避免重复映射 db.execute("INSERT OR IGNORE INTO shows_genres (show_id, genre_id) VALUES (?, ?)", show_id, genre_id)
关键修改说明
- 表结构优化:给
shows.title、genres.genre加UNIQUE约束,给shows_genres加联合主键,从存储层避免重复数据 - 去重逻辑完善:字典表都用
INSERT OR IGNORE插入,插入后通过字段值查询主键ID,保证ID获取正确 - 关联逻辑修正:关联表插入移到分类遍历循环内,保证多类型影视每个分类都有正确映射
- 可选别名配置:如果需要将长名称影视替换为简写,直接修改
title_alias字典即可匹配期望输出的名称格式
内容的提问来源于stack exchange,提问作者Minh
相关产品推荐
相关产品推荐

