SQL重复密钥冲突后继续执行查询

时间:2010-06-25 18:56:43

标签: sql database postgresql

我有一种情况,如果它不存在我想插入一行,如果已经存在则不插入它。我尝试创建阻止这种情况发生的SQL查询(请参阅here),但我被告知解决方案是创建约束并在违反时捕获异常。

我已经有了约束。我的问题是 - 如何捕获异常并继续执行更多查询?如果我的代码如下:

cur = transaction.cursor()

#execute some queries that succeed

try:
    cur.execute(fooquery, bardata)  #this query might fail, but that's OK
except psycopg2.IntegrityError:
    pass

cur.execute(fooquery2, bardata2)

然后我在第二次执行时遇到错误:

psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block

如何告诉计算机我希望它继续执行查询?我不想transaction.commit(),因为我可能想要回滚整个事务(之前成功的查询)。

2 个答案:

答案 0 :(得分:4)

我认为你可以做的是在尝试执行可能导致违规的语句之前使用SAVEPOINT。如果违规发生,那么您可以回滚到SAVEPOINT,但保留原始交易。

这是另一个可能有帮助的主题: Continuing a transaction after primary key violation error

答案 1 :(得分:1)

我对SAVEPOINT答案进行了投票 - 特别是因为它链接到我的答案被接受的问题。 ;)

但是,鉴于您在评论部分中的陈述,您预期错误“通常是”,我可以建议另一种选择吗?

这个解决方案实际上回到了你的另一个问题。这里的不同之处在于如何将数据快速加载到正确的位置和格式以便围绕单个SELECT移动数据 - 并且 - 对于您要填充的任何表都是通用的(因此相同的代码可以用于多个不同的表) )。这是我在纯PostgreSQL中如何做到的粗略布局,假设我有一个CSV文件,其格式与要插入的表的格式相同:

CREATE TEMP TABLE input_file (LIKE target_table);

COPY input_file FROM '/path/to/file.csv' WITH CSV;

INSERT INTO target_table
SELECT * FROM input_file
WHERE (<unique key field list>) NOT IN (
    SELECT <unique key field list>
    FROM target_table
);

好的,这是一个理想化的例子,我也在讨论几件事情(例如报告重复项,通过Python内存数据将数据推送到表中,从STDIN而不是通过文件复制等等)。 ),但希望基本的想法是存在的,如果你期望更多的记录被拒绝而不是被接受,它将避免大量的开销。