With SqlAlchemy, is it possible to build a query which will update only the first matching row?
In my case, I need to update the most recent log entry:
class Log(Base):
__tablename__ = 'logs'
id = Column(Integer, primary_key=True)
#...
analyzed = Column(Boolean)
session.query(Log) \
.order_by(Log.id.desc()) \
.limit(1) \
.update({ 'analyzed': True })
Which results into:
InvalidRequestError: Can't call Query.update() when limit() has been called
It makes sense, since UPDATE ... LIMIT 1
is a MySQL-only feature (with the solution given here)
But how would I do the same with PostgreSQL? Possibly, using the subquery approach?
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.
This SQLAlchemy engine is a global object which can be created and configured once and use the same engine object multiple times for different operations. The first step in establishing a connection with the PostgreSQL database is creating an engine object using the create_engine() function of SQLAlchemy.
Instead of returning entire model instances, SQLAlchemy can fetch only the columns we're interested in. This not only reduces the amount of data sent, but also avoids the need to instantiate entire objects. Working with tuples of column data instead of models can be quite a bit faster.
lazy = 'dynamic': When querying with lazy = 'dynamic', however, a separate query gets generated for the related object. If you use the same query as 'select', it will return: You can see that it returns a sqlalchemy object instead of the city objects.
The subquery recipe is the right way to do it, now we only need to build this query with SqlAlchemy.
Let's start with the subquery:
sq = ssn.query(Log.id) \
.order_by(Log.id.desc()) \
.limit(1) \
.with_for_update()
And now use it with as_scalar() with the example from the update() docs:
from sqlalchemy import update
q = update(Log) \
.values({'analyzed': True}) \
.where(Log.id == sq.as_scalar())
Print the query to have a look at the result:
UPDATE logs
SET analyzed=:analyzed
WHERE logs.id = (
SELECT logs.id
FROM logs ORDER BY logs.id DESC
LIMIT :param_1
FOR UPDATE
)
Enjoy!
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