2014-09-21 211 views
20

我想在使用SQLAlchemy模块(不是SQL!)的python中编写批量upsert。SQLAlchemy - 在postgresql中执行批量upsert(如果存在,更新,否则插入)

我得到一个SQLAlchemy的下面的错误添加:

sqlalchemy.exc.IntegrityError: (IntegrityError) duplicate key value violates unique constraint "posts_pkey" 
DETAIL: Key (id)=(TEST1234) already exists. 

我有一个表叫posts与上id列主键。

在这个例子中,我已经在db中有一行id=TEST1234。当我试图db.session.add()一个新的帖子对象与id设置为TEST1234,我得到上述错误。我的印象是,如果主键已经存在,记录会被更新。

如何根据主键单独添加Flask-SQLAlchemy?有一个简单的解决方案吗?

如果没有,我总是可以检查并删除任何带有匹配ID的记录,然后插入新记录,但这对我的情况来说似乎很昂贵,我不希望有很多更新。

+0

有一个在SQLAlchemy中没有更新插入操作,这是一般人很难即使在SQLAlchemy之外也能正确执行。显示你正在做什么来得到这个错误。 – davidism 2014-09-22 01:01:02

+1

@davidism合并操作就像一个upsert – mgoldwasser 2014-09-24 14:04:46

+1

* SQLAlchemy的'merge'不是upsert *,[upserts很难](http://lucumr.pocoo.org/2014/2/16/a-case-for -upserts /)。 merge并不是线程安全的,全部都是用Python完成的,而不是数据库。 – davidism 2014-09-24 14:45:34

回答

16

有一个在SQLAlchemy的一个更新插入式的操作:

db.session.merge()

我发现这个命令后,我能够执行upserts,但值得一提的是,该操作是批量慢“更新插入”。

另一种方法是让你想UPSERT主键的列表,并查询任何匹配的IDS数据库:

# Imagine that post1, post5, and post1000 are posts objects with ids 1, 5 and 1000 respectively 
# The goal is to "upsert" these posts. 
# we initialize a dict which maps id to the post object 

my_new_posts = {1: post1, 5: post5, 1000: post1000} 

for each in posts.query.filter(posts.id.in_(my_new_posts.keys())).all(): 
    # Only merge those posts which already exist in the database 
    db.session.merge(my_new_posts.pop(each.id)) 

# Only add those posts which did not exist in the database 
db.session.add_all(my_new_posts.values()) 

# Now we commit our modifications (merges) and inserts (adds) to the database! 
db.session.commit() 
+3

合并不处理intigirtyError – 2016-02-04 12:02:02

+1

上面的过程很慢,无法使用 – 2016-02-04 12:03:21

+1

替代方案是SQLAlchemy中upsert的一个很好的解决方案 – 2016-08-19 16:07:33

相关问题