ske*_*n3r 11 python sqlalchemy sql-update
如何使用将一列的现有值映射到另一列所需的新值的字典更新数据库中的多个现有行?
我有一张桌子:
class MyTable(BaseModel):
col1 = sa.Column(sa.String(256))
col2 = sa.Column(sa.String(256))
Run Code Online (Sandbox Code Playgroud)
鉴于col1已经有值并且col2为空,col2如果我将数据集作为字典,我该如何更新:
payload = {'x': 'y', 'a': 'b', 'c': 'd'}
Run Code Online (Sandbox Code Playgroud)
因此,此有效负载将 , 的值映射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)
Run Code Online (Sandbox Code Playgroud)
或者像这样
for key, value in payload.items():
query = session.query(MyTable).filter(MyTable.col1==key)
query.update({MyTable.col2: value})
Run Code Online (Sandbox Code Playgroud)
现在这两种解决方案都按预期工作,唯一困扰我的是它所花费的时间,例如,对于 100 个元素的有效载荷,它最多需要 6 秒,我几乎可以肯定应该有更好的方法这样做,不是吗?
我在想是否有办法让它与in_函数一起工作:
query(MyTable).filter(
MyTable.col1.in_(payload.keys())
)
Run Code Online (Sandbox Code Playgroud)
但我不知道如何构建更新查询。
Mar*_*ers 20
是的,使用单个批量UPDATE语句更新大量行比UPDATE在每个对象上使用单独的s快得多。一个IN过滤器只会帮助你限制哪些行被更新,但你仍然需要告诉使用什么值的数据库col2更新。
您可以CASE ... WHEN ... THEN为此使用构造case()函数:
from sqlalchemy.sql import case
query(MyTable).filter(
MyTable.col1.in_(payload)
).update({
MyTable.col2: case(
payload,
value=MyTable.col1,
)
}, synchronize_session=False)
Run Code Online (Sandbox Code Playgroud)
上面的 a) 选择col1值是payload字典中键的行,然后 b)col2使用CASE从同一字典中选取值的语句更新列值,以根据col1与键的匹配来更新该列。
与payload设置为{'x': 'y', 'a': 'b', 'c': 'd'},上述执行以下查询(给予或采取的确切顺序WHEN中的所有条款和值IN试验):
from sqlalchemy.sql import case
query(MyTable).filter(
MyTable.col1.in_(payload)
).update({
MyTable.col2: case(
payload,
value=MyTable.col1,
)
}, synchronize_session=False)
Run Code Online (Sandbox Code Playgroud)
我设置synchronize_session到False那里,因为MyTable在更新大量行时,一次更新所有可能的缓存实例可能不是最好的主意。您的其他选项是'evaluate'和'fetch'。
我们不能使用默认值'evaluate'(它会在会话中找到与where子句匹配的现有对象,以进行就地更新),因为 SQLAlchemy 当前不知道如何处理IN过滤器(你会得到一个UnevaluatableError异常)。
如果您确实使用,'fetch'则MyTable会话中受影响的所有缓存实例都将更新为新值col2(由它们的主键映射)。
请注意,提交无论如何都会使会话过期,因此您只希望'fetch'在提交当前事务之前需要对更新的行做更多工作时才使用。
有关您拥有的选项的更多信息,请参阅Query.update()文档synchronize_session。
| 归档时间: |
|
| 查看次数: |
18817 次 |
| 最近记录: |