首页 > 解决方案 > SqlAlchemy 按关系数查询和过滤

问题描述

所以目前我有两门课FooBar在哪里

class Foo(db.Model):
    ...
    bars = db.relationship('Bar', backref='foo', lazy='dynamic')
    ...

在这里,一个Foo可以有很多个Bar。如何查询Foo以便可以按 's 的数量进行过滤Bar?就像是Foo.query.filter(Foo.bars.count() == x).first()

除了保持计数变量之外,还有其他方法可以做到这一点吗?

标签: pythonsqlalchemyflask-sqlalchemy

解决方案


此 SQL 查询将是执行此操作的一种方式(假设 x = 2):

SELECT parent.id, COUNT(child.tid) AS num_bars 
  FROM parent 
  JOIN child ON parent.id = child.tid 
  GROUP BY parent.id 
  HAVING COUNT(child.tid) = 2;

这将转化为(sqlalchemy):

import sqlalchemy as sa

x = 2
q = (session.query(Foo, sa.func.count(Bar.foo_id).label('num_bars'))
            .join(Bar)
            .group_by(Foo.id)
            .having(sa.literal_column('num_bars') == x)
            .from_self(Foo))

flask-sqlalchemy 的等价物可能是

q = (db.session.query(Foo, sa.func.count(Bar.foo_id).label('num_bars'))
              .join(Bar)
              .group_by(Foo.id)
              .having(sa.literal_column('num_bars') >= x)
              .from_self(Foo))

另一种方法是使用子查询:

SELECT parent.id 
FROM parent 
  WHERE (SELECT COUNT(1)
         FROM child 
           WHERE child.tid = parent.id
  ) = 2

使用 SQLAlchemy 看起来像这样:

subq = (session.query(sa.func.count(Bar.foo_id))
               .filter(Bar.foo_id == Foo.id)
               .scalar_subquery())
q = session.query(Foo).filter(subq == 2)

推荐阅读