如何使用func作为sqlalchemy中的值执行批量更新?

时间:2017-02-06 20:52:45

标签: python sqlalchemy

我的数据库结构如下所示:

当前值

| file_id | file_path   | 
+---------+-------------+
|  1      | path\test   |
+---------+-------------+
|  2      | path\test2  |
+---------+-------------+
|  2      | path\test3  |
+---------+-------------+

使用sqlalchemy,我尝试使用func.replace将反斜杠替换为file_path列中的正斜杠。

期望值

| file_id | file_path   | 
+---------+-------------+
|  1      | path/test   |
+---------+-------------+
|  2      | path/test2  |
+---------+-------------+
|  3      | path/test3  |
+---------+-------------+

截至目前,我正在单独更新每一行,并且我能够毫无问题地执行替换

from sqlalchemy import Table, MetaData, Column, Integer, String, func, create_engine

table = Table('file_table', MetaData(), Column('id', Integer), Column('file_path', String))
file_ids = [1, 2, 3]

connection = create_engine('connections_string')
cursor = connection.connect()

for file_id in file_ids:
    q_ = table.update().values({'file_path': func.replace(table.c.file_path, '\\', '/')}).where(table.c.file_id == file_id)
    cursor.execute(query)

cursor.close()

我试图将其转换为批量更新,而不是单独进行每次更新。我以前做过批量更新,以下是我通常会执行一次

的方式
scripts = [{'file_path': 'new_column_value', 'bk_file_id': f} for f in [1,2,3]]
q_ = table.update().where(table.c.file_id == bindparam('bk_file_id'))
cursor.execute(q_, scripts)

以上情况正常,但在实施func.replace

时不起作用
scripts = [{'file_path': func.replace(table.c.file_path, '\\', '/'), 'bk_file_id': f} for f in [1,2,3]]
q_ = table.update().where(table.c.file_id == bindparam('bk_file_id'))
cursor.execute(q_, scripts)

回溯

Traceback (most recent call last):
  File "bulk_update.py", line 15, in <module>
    cursor.execute(q_,scripts)
  File "C:\Python35\lib\site-packages\sqlalchemy\engine\base.py", line 914, in execute
    return meth(self, multiparams, params)
  File "C:\Python35\lib\site-packages\sqlalchemy\sql\elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "C:\Python35\lib\site-packages\sqlalchemy\engine\base.py", line 1010, in _execute_clauseelement
    compiled_sql, distilled_params
  File "C:\Python35\lib\site-packages\sqlalchemy\engine\base.py", line 1146, in _execute_context
    context)
  File "C:\Python35\lib\site-packages\sqlalchemy\engine\base.py", line 1344, in _handle_dbapi_exception
    util.reraise(*exc_info)
  File "C:\Python35\lib\site-packages\sqlalchemy\util\compat.py", line 186, in reraise
    raise value
  File "C:\Python35\lib\site-packages\sqlalchemy\engine\base.py", line 1116, in _execute_context
    context)
  File "C:\Python35\lib\site-packages\sqlalchemy\dialects\mysql\mysqldb.py", line 95, in do_executemany
    rowcount = cursor.executemany(statement, parameters)
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 195, in executemany
    self.rowcount = sum(self.execute(query, arg) for arg in args)
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 195, in <genexpr>
    self.rowcount = sum(self.execute(query, arg) for arg in args)
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 164, in execute
    query = self.mogrify(query, args)
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 143, in mogrify
    query = query % self._escape_args(args, conn)
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 123, in _escape_args
    return dict((key, conn.literal(val)) for (key, val) in args.items())
  File "C:\Python35\lib\site-packages\pymysql\cursors.py", line 123, in <genexpr>
    return dict((key, conn.literal(val)) for (key, val) in args.items())
  File "C:\Python35\lib\site-packages\pymysql\connections.py", line 800, in literal
    return self.escape(obj, self.encoders)
  File "C:\Python35\lib\site-packages\pymysql\connections.py", line 793, in escape
    return escape_item(obj, self.charset, mapping=mapping)
  File "C:\Python35\lib\site-packages\pymysql\converters.py", line 27, in escape_item
    val = encoder(val, mapping)
  File "C:\Python35\lib\site-packages\pymysql\converters.py", line 110, in escape_unicode
    return u"'%s'" % _escape_unicode(value)
  File "C:\Python35\lib\site-packages\pymysql\converters.py", line 73, in _escape_unicode
    return value.translate(_escape_table)
  File "C:\Python35\lib\site-packages\sqlalchemy\sql\elements.py", line 738, in __getattr__
    key)
AttributeError: Neither 'Function' object nor 'Comparator' object has an attribute 'translate'

如何使用func来解决此错误以执行批量更新?

1 个答案:

答案 0 :(得分:1)

您的问题来自于executemany values形式的executemany不支持表达式,但对于批量更新,您不应该使用UPDATE file_table SET file_path = replace(file_path, '\\', '/') WHERE file_id = 1; UPDATE file_table SET file_path = replace(file_path, '\\', '/') WHERE file_id = 2; UPDATE file_table SET file_path = replace(file_path, '\\', '/') WHERE file_id = 3; 表单。

基本上你以前做的是:

UPDATE file_table SET file_path = replace(file_path, '\\', '/') WHERE file_id IN (1, 2, 3);

您正试图通过批量更新模仿确切的查询。为什么不改为运行单个查询呢?

table.update().values({'file_path': func.replace(table.c.file_path, '\\', '/')}).where(table.c.file_id.in_(file_ids))

在SQLAlchemy中这样做的方式与您之前完成的工作完全相同:

UserData