关于python:SQLAlchemy – 在postgresql中执行批量upsert(如果存在,更新,否则插入)

SQLAlchemy - performing a bulk upsert (if exists, update, else insert) in postgresql

本问题已经有最佳答案,请猛点这里访问。

我正在尝试使用SQLAlchemy模块在python中编写批量upsert(而不是在SQL中!)。

我在SQLAlchemy添加上收到以下错误:

1
2
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的记录,然后插入新记录,但这对我的情况来说似乎很昂贵,我不希望有很多更新。


SQLAlchemy中有一个upsert-esque操作:

db.session.merge()

在我找到这个命令后,我能够执行upserts,但值得一提的是,对于批量"upsert",这个操作很慢。

另一种方法是获取要插入的主键列表,并在数据库中查询任何匹配的ID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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()