Working with MySQL, I'd like to generate this SQL:
UPDATE tableA
INNER JOIN tableB
ON tableA.some_id = tableB.some_id
SET tableA.foo = 1
WHERE tableB.bar IN ('baz','baaz')
This is my SQLAlchemy query:
session.query(tableA).join(tableB, tableA.some_id == tableB.some_id) \
.filter(tableB.bar.in_(['baz','baaz']))\
.update({tableA.foo: 1})
But the SQL it generates is this (a multi-table update, with no join condition, which is not what I want):
UPDATE tableA, tableB
SET tableA.foo = 1
WHERE tableB.bar IN ('baz','baaz')
I've tried changing the .join into another .filter to specify the join condition, that didn't solve the problem. How do I force this simple update statement to do the proper join?
Update table elements in SQLAlchemy. Get the books to table from the Metadata object initialized while connecting to the database. Pass the update query to the execute() function and get all the results using fetchall() function. Use a for loop to iterate through the results.
I've found that the following works to join two tables: result = session. query(User, Document). select_from(join(User, Document)). filter(User.
all() method. The Query object, when asked to return full entities, will deduplicate entries based on primary key, meaning if the same primary key value would appear in the results more than once, only one object of that primary key would be present.
The Query.join()method currently supports several usage patterns and arguments that are considered to be legacy as of SQLAlchemy 1.3. A deprecation path will follow in the 1.4 series for the following features: Joining on relationship names rather than attributes: session.query(User).join("addresses")
New in version 1.4. SQLAlchemy 2.0 will standardize the production of SELECT statements across both Core and ORM by making direct use of the Select object within the ORM, removing the need for there to be a separate Query object. This mode of operation is available in SQLAlchemy 1.4 right now to support applications that will be migrating to 2.0.
The SQLAlchemy ORM is based around the concept of an identity map such that when an object is “loaded” from a SQL query, there will be a unique Python object instance maintained corresponding to a particular database identity.
methodsqlalchemy.orm.Query.from_statement(statement)¶ Execute the given SELECT statement and return results. This method bypasses all internal statement compilation, and the statement is executed without modification.
As of version 0.7.4 sqlalchemy.sql.expression.update does allow you to refer to multiple tables in the WHERE clause. With this, you could build and execute an expression like:
users.update().values(name='ed').where(
users.c.name==select([addresses.c.email_address]).\
where(addresses.c.user_id==users.c.id).\
as_scalar()
)
(example straight from the link above)
The problem ValAyal is having is actually because Query.join()
is not supported with Query.update()
. Unfortunately, until 0.9.1 this was silently generating queries like the one ValAyal shared above. The changelog notes for 0.9.1 notes that the behavior was modified to emit a warning:
[orm] [bug] Query doesn’t support joins, subselects, or special FROM clauses when using the Query.update() or Query.delete() methods; instead of silently ignoring these fields if methods like Query.join() or Query.select_from() has been called, a warning is emitted. As of 1.0.0b5 this will raise an error.
References: #3349
We actually ran into this where I work just this evening and found that our code is, in fact, emitting the following warning (which says it will an error in 1.0):
SAWarning: Can't call Query.update() or Query.delete() when join(), outerjoin(), select_from(), or from_self() has been called. This will be an exception in 1.0
self._validate_query_state()
In our case, we opted to convert the update into a select and an update to one table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With