2017-03-01 208 views
0
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要做到這一點,我結束了這個錯誤如何在SQLAlchemy ORM中表示多表更新(UPDATE FROM)?

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

我想使用ORM,從而使會話將更新命令完成之前的變化進行更新。

+0

你能否也請包括你正在嘗試使用的實際查詢?你的例子也是不完整的,因爲你不能在這些表中使用ORM,因爲它們缺少主鍵,除非你在表參數中傳遞* name *作爲候選鍵。 –

+0

我已經將大得多的表格煮到了證明問題所需的最低限度。 – boatcoder

回答

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'

+0

SqlAlchemy似乎不會自動執行這麼多操作(例如,讓我稱之爲「aliased」),我已經打消了它在過濾語句中取得未聯合表的能力。 – boatcoder

+0

在我以前的工作中,我們實際上是通過'filter()'中的隱式表引用「咬」的,導致了一些大量的隱式交叉連接:P。有什麼值得注意的地方... –

相關問題