Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
399 views
in Technique[技术] by (71.8m points)

python - How do you express a multi table update (UPDATE FROM) in SQLAlchemy ORM?

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;

When I try to do this with the ORM, I end up with this error

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

I want to use the ORM so that the session will be updated with the changes before the update command completes.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's how you'd issue your multi table update using the ORM:

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)

The footnote in the Query API documentation for update links to the Core multi table update docs:

The SQLAlchemy update() construct supports both of these modes implicitly, by specifying multiple tables in the WHERE clause

which expands to the ORM Query API as well, which is no surprise as the ORM is built on top of Core. The resulting query is:

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

From your error I suspect you have something along the lines of

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

which as the error states is not accepted. You have to pass the FROM table implicitly in the WHERE clause, e.g. filter() in the Query API.

To achieve

I'm wanting to use the ORM so that the session will be updated with the changes before the update command completes.

you'll have to change the synchronize_session accordingly to either 'fetch' or 'evaluate'.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...