python - SQLAlchemy 在一个事务中更新多行

标签 python sqlalchemy sql-update

如何使用将一列的现有值映射到另一列所需的新值的字典更新数据库中的多个现有行?

我有一张 table :

class MyTable(BaseModel):
    col1 = sa.Column(sa.String(256))
    col2 = sa.Column(sa.String(256))

鉴于 col1已经有值和 col2为空,如何更新 col2如果我有一组数据作为字典:
payload = {'x': 'y', 'a': 'b', 'c': 'd'}

所以这个有效载荷映射了 col1 的值, 到 col2 的新值;更新后你会得到 [{'col1': 'x', 'col2': 'y'}, ...]从数据库。

我尝试了几种方法,它们实际上有效,但我认为它们并不像它可能的那样最佳:
my_table = MyTable.__table__
for key, value in payload.items():
    stm = my_table.update()
    stm = stm.where(getattr(sales_order_item.c, 'col1') == key)
    stm = stm.values({'col2': value})
    session.execute(stm)

或者像这样
for key, value in payload.items():
    query = session.query(MyTable).filter(MyTable.col1==key)
    query.update({MyTable.col2: value})

现在这两种解决方案都按预期工作,唯一困扰我的是它所花费的时间,例如,对于 100 个元素的有效载荷,它最多需要 6 秒,我几乎可以肯定应该有更好的方法这样做,不是吗?

我在想是否有办法让它与 in_ 一起工作功能:
query(MyTable).filter(
        MyTable.col1.in_(payload.keys())
    )

但我不知道如何构建更新查询。

最佳答案

是的,使用单个批量更新更多行 UPDATE语句将比使用单个 UPDATE 快得多s 在每个对象上。安 IN filter 只会帮助您限制更新的行,但您仍然需要告诉数据库要为 col2 使用什么值更新。

您可以使用 CASE ... WHEN ... THEN为此构造,使用 case() function :

from sqlalchemy.sql import case

query(MyTable).filter(
    MyTable.col1.in_(payload)
).update({
    MyTable.col2: case(
        payload,
        value=MyTable.col1,
    )
}, synchronize_session=False)

上面的 a) 选择 col1 所在的行value 是 payload 中的一个键字典,然后 b) 更新 col2列值使用 CASE从同一字典中选择值以根据匹配更新该列的语句 col1反对 key 。

payload设置为 {'x': 'y', 'a': 'b', 'c': 'd'} ,上面执行以下查询(给出或采用 WHEN 测试中 IN 子句和值的确切顺序):

UPDATE mytable
SET
    col2=CASE mytable.col1
        WHEN 'x' THEN 'y'
        WHEN 'a' THEN 'b'
        WHEN 'c' THEN 'd'
    END
WHERE
    mytable.col1 IN ('x', 'a', 'c')

我设置了synchronize_sessionFalse在那里,更新所有可能的缓存 MyTable在更新大量行时,一次实例可能不是最好的主意。您的其他选择是 'evaluate''fetch' .
  • 我们不能使用默认的 'evaluate' (它将在 session 中找到匹配 where 子句的现有对象,以进行就地更新),因为 SQLAlchemy 当前不知道如何处理 IN过滤器(您会收到 UnevaluatableError 异常)。
  • 如果您确实使用 'fetch'那么 MyTable 的所有实例缓存在受影响的 session 中,更新为 col2 的新值。 (由它们的主键映射)。

  • 请注意,提交无论如何都会使 session 过期,因此您只想使用 'fetch'如果在提交当前事务之前需要对更新的行做更多的工作。

    Query.update() documentation有关什么的更多信息 synchronize_session你有的选择。

    关于python - SQLAlchemy 在一个事务中更新多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54365873/

    相关文章:

    python - 如何在 SQLAlchemy 中将 joinedload/contains_eager 用于启用查询的关系(惰性 ='dynamic' 选项)

    sql - 永远更新查询

    python - Matplotlib : Could not convert string to float

    python - 将时间戳转换为槽。 Python。 Pandas

    python - 在 Win10 机器上更新 scikit-learn 时出现“_remove_dead_weakref”错误

    python - SQLAlchemy,JSONB字段没有删除状态的历史记录

    python - 将列插入我数据库中的所有表

    python - 删除数字刻度并保留列名称

    sql - SQL更新撤消

    Mysql语法更新设置值字符串替换为另一列的值