如何使用将一列的现有值映射到另一列所需的新值的字典更新数据库中的多个现有行?
我有一张 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_session
至 False
在那里,更新所有可能的缓存 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/