Ошибка массового обновления sqlalchemy

У меня есть таблица = foo (минимальный пример ниже):

house       processed
----------  ----------
95.0
10.0
63.0
6.0
55.0
1.0
19.0
1.0
30.0
21.0
sprite

Я хочу изменить десятичные значения на целые числа и узнать, когда в этом столбце есть нечисловое значение. Я пробовал с конструкцией query.filter().update(), и хотя это дает мне то, что я хочу, для 100 тыс. строк это занимает вечность. Я понял, что bulk_update может мне помочь. Но может я что-то не так делаю. Мой код:

class foo(Base):
    __tablename__ = "foo"
    rowid = Column(Integer, primary_key=True)
    house = Column(Float)
    processed = Column(String(255))

mappings = []
for idx, s in enumerate(session.query(foo), start=1):    
    if type(s.house) in (int, float):
        replace = int(s.house)            
        info = {'processed':replace}
    else:
        info = {'processed':'not number'}        
    mappings.append(info)  
session.bulk_update_mappings(foo, mappings)
session.commit()

сопоставления [{'обработано': 95}, {'обработано': 10}, {'обработано': 63}, {'обработано': 6}, {'обработано': 55}, {'обработано': 1}, {'обработано': 19}, {'обработано': 1}, {'обработано': 30}, {'обработано': 21}, {'обработано': 'не число'}]

Это дает мне ошибку:

Ожидается, что оператор UPDATE для таблицы 'foo' обновит 11 строк; 0 были сопоставлены

Полная ошибка:

session.bulk_update_mappings(foo, mappings)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\M64H098\repo\Enrichments-bag\lib\site-packages\sqlalchemy\orm\session.py", line 2868, in bulk_update_mappings
    self._bulk_save_mappings(
  File "C:\Users\M64H098\repo\Enrichments-bag\lib\site-packages\sqlalchemy\orm\session.py", line 2885, in _bulk_save_mappings
    transaction = self.begin(subtransactions=True)
  File "C:\Users\M64H098\repo\Enrichments-bag\lib\site-packages\sqlalchemy\orm\session.py", line 947, in begin
    self.transaction = self.transaction._begin(nested=nested)
  File "C:\Users\M64H098\repo\Enrichments-bag\lib\site-packages\sqlalchemy\orm\session.py", line 316, in _begin
    self._assert_active()
  File "C:\Users\M64H098\repo\Enrichments-bag\lib\site-packages\sqlalchemy\orm\session.py", line 288, in _assert_active
    raise sa_exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: UPDATE statement on table 'foo' expected to update 11 row(s); 0 were matched. (Background on this error at: http://sqlalche.me/e/7s2a)

Что я могу сделать, чтобы массово обновить столбец processed с помощью словаря mapping?


person Kay    schedule 27.03.2020    source источник
comment
Вам необходимо включить идентификаторы строк, чтобы сообщить базе данных, какие строки следует обновить [{'id': 42, 'processed': 111}, ...]   -  person snakecharmerb    schedule 28.03.2020
comment
@snakecharmerb да! это работает, спасибо. Не могли бы вы опубликовать это как ответ, чтобы я мог пометить его как правильный :)   -  person Kay    schedule 30.03.2020


Ответы (1)


bulk_update_mappings требует, чтобы первичные ключи для обновляемых строк были включены в словари обновления. Это имеет смысл, если подумать — у базы данных должен быть способ идентифицировать строки, которые должны быть обновлены. В этом случае первичными ключами будут rowid модели Foo.

info = {'rowid': s.rowid, 'processed':replace}

Из документов (выделено мной):

последовательность словарей, ... Все те ключи, которые присутствуют и не являются частью первичного ключа, применяются к предложению SET оператора UPDATE; обязательные значения первичного ключа применяются к предложению WHERE.

person snakecharmerb    schedule 30.03.2020