SQLAlchemy update multiple rows in one transaction
Yes, updating a larger number of rows with a single bulk UPDATE
statement will be a lot faster than using individual UPDATE
s on each and every object. An IN
filter would only help you limit what rows are updated, but you still need to tell the database what value to use for the col2
updates.
You can use a CASE ... WHEN ... THEN
construct for that, with the case()
function:
from sqlalchemy.sql import case
query(MyTable).filter(
MyTable.col1.in_(payload)
).update({
MyTable.col2: case(
payload,
value=MyTable.col1,
)
}, synchronize_session=False)
The above a) selects rows where the col1
value is a key in the payload
dictionary, then b) updates the col2
column value using a CASE
statement that picks values from that same dictionary to update that column based on matching col1
against the keys.
With payload
set to {'x': 'y', 'a': 'b', 'c': 'd'}
, the above executes the following query (give or take the exact order of WHEN
clauses and values in the IN
test):
UPDATE mytable
SET
col2=CASE mytable.col1
WHEN 'x' THEN 'y'
WHEN 'a' THEN 'b'
WHEN 'c' THEN 'd'
END
WHERE
mytable.col1 IN ('x', 'a', 'c')
I set synchronize_session
to False
there, as updating all possible cached MyTable
instances at once is perhaps not the best idea when updating a large number of rows. Your other options are 'evaluate'
and 'fetch'
.
We can't use the default
'evaluate'
(which would find existing objects in the session that match thewhere
clause, to update in-place), because SQLAlchemy currently doesn't know how to process anIN
filter (you get anUnevaluatableError
exception).If you do use
'fetch'
then all instances ofMyTable
cached in the session that were affected are updated with new values forcol2
(as mapped by their primary key).
Note that a commit would expire the session anyway, so you'd only want to use 'fetch'
if you need to do some more work with the updated rows before you can commit the current transaction.
See the Query.update()
documentation for more information on what synchronize_session
options you have.
How to update SQLAlchemy row entry?
user.no_of_logins += 1
session.commit()
Run UPDATE SET parameterized sql statement in Connection.execute sqlalchemy
The bind params aren't MySQL style, and as you're passing in plain text to engine.execute()
, SQLAlchemy isn't applying a dialect to the query before executing it.
Try this:
engine.execute("SELECT :val", {"val": 1}) # will fail, same as your query
...and then this:
engine.execute("SELECT %(val)s", {"val": 1}) # will execute
Wrapping the query with text()
will let SQLAlchemy handle the proper bind style:
from sqlalchemy import text # or you can use db.text w/ flask-sqlalchemy
engine.execute(text("SELECT :val"), {"val": 1})
One other thing to note is that SQLAlchemy will automatically handle construction of the UPDATE query for you, respecting the values in the parameter dict, e.g.:
id_ = 1
params = {'username': "testing", "email": "testing@testing.ts"}
User.__table__.update().values(params).where(id=id_)
# UPDATE user SET username=%(username)s, email=%(email)s WHERE user.id = %(id_1)s
params = {'username': "testing"}
User.__table__.update().values(params).where(id=id_)
# UPDATE user SET username=%(username)s WHERE user.id = %(id_1)s
params = {'username': "testing", "unexpected": "value"}
User.__table__.update().values(params).where(id=id_)
# sqlalchemy.exc.CompileError: Unconsumed column names: unexpected
SQLAlchemy: update from_select
Assuming that t_node
is node
Table instance, while t_node_node
- node_node
Table instance, see the statement below.
upd = (t_node.update()
.values(
parent_id = t_node_node.c.parent_id,
label = t_node_node.c.label,
)
.where(t_node_node.c.child_id == t_node.c.node_id)
)
Read more on Inserts, Updates and Deletes documentation for more information.
Flask-SQLAlchemy with_for_update() row lock
After struggling for one whole day, i found the problem.
user = User.query.with_for_update().filter_by(id=userid).first()
should be
result = db.session.query(User.money).with_for_update().filter_by(id=userid).first()
money = result[0]
user.money = money - 0.1
Yes, so simple but annoying
Updating a row using SQLAlchemy ORM
I believe you are looking for something like this for your update query:
session.query(FoobarModel).filter(FoobarModel.id == foobar_id).update({'name': 'New Foobar Name!'})
Since update()
belongs to Query, and filter()
does return a Query
object, this will work, contrary to trying to call update()
on your FoobarModel
object (which does not have such a function) returned by Query.get()
, see also here.
As for looping over your properties and assigning them by name, you could do this with setattr
and a dict, like this:
foobar = session.query(FoobarModel).get(foobar_id)
props = {'name': 'my new name'}
for key, value in props.items():
setattr(foobar, key, value)
session.commit()
session.flush()
This is obviously a little pointless with just one property, but maybe it will come in handy at some point.
Related Topics
Python Does Not Match Format '%Y-%M-%Dt%H:%M:%S%Z.%F'
How to Compile Multiple Python Files into Single .Exe File Using Pyinstaller
How Can One Modify the Outline Color of a Node in Networkx
How to Print Numbers in a List That Are Less Than a Variable. Python
Testing Whether a String Has Repeated Characters
Iterate Through a List by Skipping Every 5Th Element
How to Manage Division of Huge Numbers in Python
How to Find Words in a List That Starts With a Certain Letter the User Asked For
Pandas: Merging Two Columns into One With Corresponding Values
Large File Crashing on Jupyter Notebook
Airflow:Passing a Dynamic Value to Sub Dag Operator
Pandas Rank by Multiple Columns
Running Multiple Commands Simultaneously from Python
How to Get the Current Ipython/Jupyter Notebook Name
How to Find Duplicate Values in a List and Merge Them
Converting Text File into Json in a Specific Format ( Python )
Flask Installed, But Modulenotfounderror: No Module Named 'Flask'