我有2张桌子;我们称他们为table1
和table2
。 table2
有table1
的外键。我需要在table1
中删除table2
中没有子记录的行。执行此操作的SQL非常简单:
DELETE FROM table1
WHERE 0 = (SELECT COUNT(*) FROM table2 WHERE table2.table1_id = table1.table1_id);
但是,我还没有找到将此查询转换为SQLAlchemy的方法。尝试直截了当的方法:
subquery = session.query(sqlfunc.count(Table2).label('t2_count')).select_from(Table2).filter(Table2.table1_id == Table1.table1_id).subquery()
session.query(Table1).filter(0 == subquery.columns.t2_count).delete()
刚出错:
sqlalchemy.exc.ArgumentError: Only deletion via a single table query is currently supported
如何使用SQLAlchemy执行此DELETE
?
答案 0 :(得分:2)
我很确定这就是你想要的。你应该尝试一下。它使用EXISTS。
from sqlalchemy.sql import not_
# This fetches rows in python to determine which ones were removed.
Session.query(Table1).filter(not_(Table1.table2s.any())).delete(
synchronize_session='fetch')
# If you will not be referencing more Table1 objects in this session then you
# can just ignore syncing the session.
Session.query(Table1).filter(not_(Table1.table2s.any())).delete(
synchronize_session=False)
delete()的参数说明:
http://docs.sqlalchemy.org/en/rel_0_8/orm/query.html#sqlalchemy.orm.query.Query.delete
存在的示例(使用上面的any()使用EXISTS):
http://docs.sqlalchemy.org/en/rel_0_8/orm/tutorial.html#using-exists
以下是应该生成的SQL:
DELETE FROM table1 WHERE NOT (EXISTS (SELECT 1
FROM table2
WHERE table1.id = table2.table1_id))
如果你使用声明,我认为有一种方法可以访问Table2。表然后你可以使用sqlalchemy的sql层来完全按照自己的意愿行事。虽然您遇到了使会话不同步的相同问题。
答案 1 :(得分:1)
好吧,我找到了一个非常难看的方法。您可以使用连接进行选择以将行加载到内存中,然后您可以单独删除它们:
subquery = session.query(Table2.table1_id
,sqlalchemy.func.count(Table2.table2_id).label('t1count')
) \
.select_from(Table2) \
.group_by(Table2.table1_id) \
.subquery()
rows = session.query(Table1) \
.select_from(Table1) \
.outerjoin(subquery, Table1.table1_id == subquery.c.table1_id) \
.filter(subquery.c.t1count == None) \
.all()
for r in rows:
session.delete(r)
这不仅令人讨厌,而且性能也非常糟糕。对于初学者,您必须将table1
行带入内存。第二,如果你像我一样,在Table2
的班级定义中有这样的一行:
table1 = orm.relationship(Table1, backref=orm.backref('table2s'))
然后SQLAlchemy将实际执行一个查询,将相关的table2
行拉入内存(即使没有)。更糟糕的是,因为你必须遍历列表(我尝试只是传入列表;不起作用),它一次一行table1
行。因此,如果您要删除10行,则会有21个单独的查询(1表示初始选择,1表示每个关系拉,1表示每次删除)。也许有办法减轻这种情况;我必须通过文档来查看。所有这些都是我在数据库中甚至不需要的东西,更不用说内存了。
我不会将此标记为答案。我想要一种更干净,更有效的方法,但这就是我现在所拥有的一切。