【问题标题】:How do you express a multi table update (UPDATE FROM) in SQLAlchemy ORM?如何在 SQLAlchemy ORM 中表达多表更新(UPDATE FROM)?
【发布时间】:2018-11-21 12:51:09
【问题描述】:
CREATE TABLE foo (
    name text NOT NULL,
    deleted_at timestamp without time zone
);

CREATE TABLE bar (
    name text NOT NULL,
    status_id int
);

UPDATE bar set status_id=1
FROM foo
WHERE status_id <> 1 AND foo.name = bar.name AND foo.deleted_at is null;

当我尝试使用 ORM 执行此操作时,我最终会遇到此错误

InvalidRequestError: Can't call Query.update() or Query.delete() when join(), outerjoin(), select_from(), or from_self() has been called

我想使用 ORM,以便在更新命令完成之前使用更改更新会话。

【问题讨论】:

  • 能否请您也包括您尝试使用的实际查询?您的示例也不完整,因为您无法将 ORM 与这些表一起使用,因为它们缺少主键,除非您将 name 作为表 args 中的候选键传递。
  • 我已将大得多的表简化为演示问题所需的最小值。

标签: python sqlalchemy


【解决方案1】:

以下是使用 ORM 发出 multi table update 的方法:

session.query(Bar).\
    filter(Bar.status_id != 1,
           Bar.name == Foo.name,
           Foo.deleted_at.is_(None)).\
    update({Bar.status_id: 1}, synchronize_session=False)

Query API 文档中的脚注是核心多表更新文档的更新链接:

SQLAlchemy update() 构造隐式支持这两种模式,方法是在 WHERE 子句中指定多个表

它也扩展到 ORM 查询 API,这并不奇怪,因为 ORM 构建在 Core 之上。结果查询是:

UPDATE bar SET status_id=%(status_id)s
FROM foo
WHERE bar.status_id != %(status_id_1)s
  AND bar.name = foo.name
  AND foo.deleted_at IS NULL

从你的错误我怀疑你有一些类似的东西

session.query(Bar).select_from(Foo)...update(...)

不接受错误状态。您必须在 WHERE 子句中隐式传递 FROM 表,例如查询 API 中的filter()

实现

我想使用 ORM,以便在更新命令完成之前使用更改更新会话。

您必须将synchronize_session 相应地更改为'fetch''evaluate'

【讨论】:

  • 在我之前的工作中,我们实际上被filter() 中的隐式表引用“咬”了,导致一些严重的隐式交叉连接:P。需要注意的地方...
猜你喜欢
  • 1970-01-01
  • 2012-10-31
  • 1970-01-01
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-17
相关资源
最近更新 更多