在IntegrityError后继续加载

9 投票
3 回答
4076 浏览
提问于 2025-04-16 01:02

在Python中,我正在使用importmany来填充一个SQLite数据库,这样我就可以一次性导入成千上万行数据。我的数据是以元组的列表形式存储的。我已经按照我的需求设置好了数据库的主键。

我遇到的问题是,当主键出现冲突时,会抛出一个IntegrityError(完整性错误)。如果我处理这个异常,我的脚本就会在主键冲突的地方停止导入数据。


try:

try:
    self.curs.executemany("INSERT into towers values (NULL,?,?,?,?)",self.insertList)
except IntegrityError:
    print "Primary key error"
conn.commit()


所以我想问的是,在Python中使用importmany时,我能否:

1. 捕获那些违反主键的值?
2. 在遇到主键错误后继续加载数据。

我明白为什么它不继续加载,因为在发生异常后,我会将数据提交到数据库。不过,我不知道如何从我停止的地方继续导入数据。

不幸的是,我无法在这个网络上复制和粘贴所有代码,任何帮助都将非常感谢。目前我没有设置任何主键作为解决办法...

3 个回答

-1

用一个for循环来遍历这个列表,使用execute而不是executemany。把这个for循环放在try语句里,这样如果出现错误也能继续执行。大概可以这样写:

for it in self.insertList:
    try:
        self.curs.execute("INSERT into towers values (NULL,?,?,?,?)",it)
    except IntegrityError:
        #here you could insert the itens that were rejected in a temporary table
        #without constraints for later use (question 1)
        pass
conn.commit()

你甚至可以统计一下,列表里有多少项实际上被插入了。

0

你可以使用 lastrowid 来获取你停止的地方:

http://docs.python.org/library/sqlite3.html#sqlite3.Cursor.lastrowid

不过,如果你使用了这个功能,就不能再使用 executemany 了。

6

首先回答第(2)个问题,如果你想在出现错误后继续加载数据,其实在SQL这边只需要简单调整一下:

INSERT OR IGNORE INTO towers VALUES (NULL,?,?,?,?)

这样做会成功插入那些没有冲突的行,并且会优雅地忽略掉那些有冲突的行。不过要注意的是,IGNORE这个选项在外键冲突时还是会失败。

另外一个处理冲突的选项是:INSERT OR REPLACE INTO ...。我强烈建议你查看一下SQLite的文档,里面有关于冲突和解决冲突的更多信息。

据我所知,你不能同时以一种高效的方式同时实现(1)和(2)。你可能可以创建一个触发器,在插入之前捕捉到冲突的行,但这样会给所有的插入操作带来很多不必要的负担。(如果有人知道更聪明的做法,请告诉我。)所以我建议你考虑一下,是否真的需要捕捉到冲突行的值,或者是否需要重新设计你的数据库结构,如果可能的话。

撰写回答