web-dev-qa-db-ja.com

SQLAlchemy-postgresqlで一括更新(存在する場合、更新、または挿入)を実行する

SQLAlchemyモジュール(SQLではない!)を使用して、python)で一括アップサートを記述しようとしています。

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のレコードをチェックして削除し、新しいレコードを挿入できますが、多くの更新を期待していない私の状況では、コストがかかるようです。

29
mgoldwasser

SQLAlchemyにはupsert-esque操作があります。

db.session.merge()

このコマンドを見つけた後、アップサートを実行できましたが、バルク「アップサート」ではこの操作が遅いことに注意してください。

別の方法は、アップサートする主キーのリストを取得し、一致するIDについてデータベースを照会することです。

# 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()
21
mgoldwasser