我有三个具有两个一对多关系的模型对象:
Match <-> Slot <-> Player
使用backrefs 'player'
和'match'
定义关系。所以我要做的就是找到满足match_filter
过滤器的所有匹配项:
slot_filter = or_(Slot.account_id==None,
Slot.additional_units!=None)
# func.count(Slot.player.slots)<=1)
match_filter = and_(Match.human_players==10,
Match.game_mode==2,
~Match.slots.any(slot_filter))
query = session.query(Match).join(Slot)
query = query.filter(match_filter)
matches = query.all()
问题在于我真的不知道在我的查询中应该在哪里添加Player.slots,以及如何过滤掉至少有一个玩家比n次比赛少(或相等)的比赛。我已经阅读了有关group_by
,having
和func.count
方法的内容,但我仍然不了解如何在我的案例中使用它们。
修改我发现了几乎相同的问题:Filter by grandchildren count in SQLAlchemy 但我仍然没有弄清楚如何将其应用于我的人际关系
修改以下是我的解决方案:
subquery = session.query(Player.id).\
join(Slot).\
group_by(Player.id).\
having(func.count(Player.slots) > 1).\
subquery()
matches = session.query(Match).\
join(Slot).\
join(Player).\
filter(Player.id.in_(subquery)).\
filter(match_filter).all()
答案 0 :(得分:1)
前言:您必须更多地考虑在SQL
内工作,而不是在ORM中工作。
如果您想按祖父母过滤,那么 - 如果在SQL
工作 - 您显然必须执行JOIN
或使用子SELECT
。
话虽如此,在SQLAlchemy
中过滤与在纯SELECT
中进行SQL
非常接近。
HAVING
仅在RDBMS生成结果集之后才适用,因此如果结果集相当大,使用HAVING
将非常慢。所以要小心使用。
至于其他选项:
JOIN
<强>临强>
relationship
访问联接对象,则可以使用此选项使用joinedload
等预先填充这些对象。<强>缺点:强>
JOIN
,那么您的结果集当然会成倍增加以获得更多行。因此,SQLAlchemy
必须阅读更多数据(并可能将其丢弃)。根据您的数据,这会对性能产生影响。group_by
达到理智count
的原因。使用GROUP BY
的效果通常低于使用索引的情况。correlate
这些必须使用SQLAlchemy-CORE编写。例如:
subselect = (select([Player.id])
.select_from(Player.__table__.join(Slot.__table__)
.where(Player.slot_id == Slot.id)
.correlate(Slot.__table__))
这不是一个缺点。事实上,我更喜欢以这种方式使用SQLAlchemy,因为我从查询中获得了更可预测的性能。
<强>临强>
<强>缺点:强>