Sqlalchemy添加了多个记录和潜在的约束违规

时间:2016-04-13 07:54:02

标签: python sqlalchemy

我在一个柱子上有一个独特的约束表,如:

CREATE TABLE entity (
    id      INT NOT NULL AUTO_INCREMENT,
    zip_code    INT NOT NULL,
    entity_url  VARCHAR(255) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY ix_uniq_zip_code_entity_url (zip_code, entity_url)
);

和相应的SQLAlchemy模型。我添加了很多记录,并且不想在每条记录之后提交会话。我的假设是,最好多次拨打session.add(new_record),一次session.commit()

但是在添加新记录时,我可以获得IntegrityError,因为违反了约束。这是正常的情况,我想跳过这样的记录插入。但看起来我只能恢复整个交易。

此外,我不想添加另一个复杂的检查"从数据库获取所有记录,其中[...]中的zip_code和[...]中的entity_url然后从records_to_insert"中删除匹配的数据。

是否可以设置违反约束的SQLAlchemy drop记录?

2 个答案:

答案 0 :(得分:4)

  

我的假设是,最好多次拨打session.add(new_record),一次session.commit()

您可能想重新考虑这个假设。批量处理大量记录通常适用于多次提交 - 如果你有10k记录并且你的代码在9,999号引发异常怎么办?你将被迫重新开始。这里的核心问题是,在没有其他记录的情况下,其中一条记录是否存在于数据库中是否有意义。如果确实如此,那么每个条目的提交都没有问题(除了性能问题)。在这种情况下,您只需捕获IntegrityError并调用session.rollback()继续记录列表。

无论如何,类似的问题是asked on the SQLA mailing list并由图书馆的创建者迈克拜耳回答。他建议你自己从新记录列表中删除重复项,因为这很容易用字典或集合。这可以像字典理解一样简单:

new_entities = { (entity['zip_code'], entity['url']): entity for entity in new_entities}

(这会将最后看到的副本选为要添加到数据库的副本。)

另请注意,他使用SQLAlchemy核心库来执行插入,而不是使用ORM的session.add()方法:

sess.execute(Entry.__table__.insert(), params=inserts)

如果您处理大量记录(例如,他的示例中有100,000条记录),这是一个更快的选择。

答案 1 :(得分:0)

如果您决定逐行插入记录,则可以在插入之前检查它是否已存在。这可能是也可能不是更优雅和有效:

def record_exists(session, some_id):
    return session.query(exists().where(YourEntity.id == some_id)).scalar()

for item in items:
    if not record_exists(session, item.some_id):
        session.add(record)
        session.flush()
    else:
        print "Already exists, skipping..."

session.commit()