I have trouble doing such thing bottom with SQLAlchemy:
DELETE a FROM a INNER JOIN b ON b.`aId` = a.`Id` WHERE `b`.`xxx` = ?;
As the post here: SQLAlchemy: Create delete query using self-join on MySQL
I've got it's hard to do delete in SQLAlchemy with join.
So I'm now doing like this:
session.execute('DELETE a FROM a INNER JOIN b ON b.`aId` = a.`Id` WHERE `b`.`xxx` = %d;'%xxx)
But it just annoy me a lot like about: SQL Injection thing, etc..
Is there any way using SQLAlchemy to solve the problem here? Thanks!
SQLAlchemy 1.2 and up support multi table deletes for some dialects (at the time of writing Postgresql, MySQL and Microsoft SQL Server):
In [18]: a = table('a', column('x'))
In [19]: b = table('b', column('x'))
In [20]: c = table('c', column('x'), column('y'))
In [21]: a.delete().\
...: where(a.c.x == b.c.x).\
...: where(b.c.x == c.c.x).\
...: where(c.c.y == 1)
Out[21]: <sqlalchemy.sql.dml.Delete object at 0x7f3577d89160>
In [22]: print(_.compile(dialect=mysql.dialect()))
DELETE FROM a USING a, b, c WHERE a.x = b.x AND b.x = c.x AND c.y = %s
and the same using a Session
and Declarative:
In [2]: class Foo(Base):
...: __tablename__ = 'foo'
...: id = Column(Integer, primary_key=True)
In [3]: class Bar(Base):
...: __tablename__ = 'bar'
...: id = Column(Integer, primary_key=True)
...: foo_id = Column(ForeignKey(Foo.id))
...:
In [4]: class Baz(Base):
...: __tablename__ = 'baz'
...: id = Column(Integer, primary_key=True)
...: bar_id = Column(ForeignKey(Bar.id))
...: val = Column(Integer)
...:
In [5]: session.query(Foo).\
...: filter(Foo.id == Bar.foo_id,
...: Bar.id == Baz.bar_id,
...: Baz.val == 1).\
...: delete(synchronize_session=False)
...:
which would emit
DELETE FROM foo USING foo, bar, baz
WHERE foo.id = bar.foo_id AND bar.id = baz.bar_id AND baz.val = %(val_1)s
Here is the way I did it:
map_ids = session.query(Table1.map_id). \
filter(Table1.xxxx == 'xxx_value')
q = session.query(Table2). \
filter(Table2.map_id.in_(map_ids.subquery()))
q.delete(synchronize_session=False)
The key here are you create subquery by finding ids that has to be deleted. Then you use 'in_' operator to select records to be deleted. 'synchoronize_session=False' will execute query without updating session. This gives the best performance boost.
If you read the documentation for session.execute
you will see that you should do something like this:
session.execute(
'DELETE a FROM a INNER JOIN b ON b.`aId` = a.`Id` WHERE `b`.`xxx` = :param',
{"param": 5}
)
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