如何使用SqlAlchemy在连接上构造计数聚合?

时间:2015-10-25 22:41:49

标签: python sqlalchemy

我有一个用户表,这些用户可能属于的组表,以及用户和组之间的连接表。

这在SQLAlchemy中表示如下:

class User(Base):
    __tablename__ = 'user'
    user_id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)
    email = Column(String(250), nullable=False)
    groups = relationship('Group', secondary='user_group_pair')

class Group(Base):
    __tablename__ = 'group'
    group_id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)
    date_created = Column(String(250), nullable=False)
    members = relationship('User', secondary='user_group_pair')

class User_Group_Pair(Base):
    __tablename__ = 'user_group_pair'
    user_group_pair_id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('user.user_id'))
    group_id = Column(Integer, ForeignKey('group.group_id'))
    user = relationship(User, backref=backref("group_assoc"))
    group = relationship(Group, backref=backref("user_assoc"))

我试图解决以下简单问题:

我想编写一个查询,该查询将返回用户列表以及每个用户所属的组数。

这需要来自User和User_Group_Pair的数据(因此我的问题的标题引用了连接),以及按user_id分组的计数聚合。

我不确定为什么这不起作用:

subq = session.query(User_Group_Pair.user_id.label('user_id'), func.count(User_Group_Pair.user_group_pair_id).label('count')).\
group_by(User_Group_Pair.user_id).order_by('count ASC').subquery()

result = session.query(User).join(subq, User.user_id == subq.user_id).all()

我收到此错误:

'Alias' object has no attribute 'user_id'

但请注意,我已将User_Group_Pair.user_id标记为' user_id' ...有什么想法?

谢谢

2 个答案:

答案 0 :(得分:1)

http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#using-subqueries

  Query上的

subquery()方法生成一个SQL表达式构造,表示嵌入在别名中的SELECT语句。语句中的列可通过名为c。

的属性访问

您可以在查询中使用.c.column_name列名称

result = session.query(User).join(subq, User.user_id == subq.c.user_id).all()

答案 1 :(得分:1)

只需将subq.user_id更改为subq.c.user_idc代表columns)即可使其正常运行:

result = session.query(User).join(subq, User.user_id == subq.c.user_id).all()

但是,您仍然只会获得属于至少一个组的用户,并且查询结果中并未真正返回组的数量。下面的查询是解决此问题的方法:

q = (session.query(User, func.count(Group.group_id).label("num_groups"))
     .outerjoin(Group, User.groups)
     .group_by(User.user_id)
     )
for b, num_groups in q:
    print(b, num_groups)