sqlalchemy连接分组行的总和和计数

时间:2014-01-21 23:42:59

标签: sql sqlalchemy flask-sqlalchemy

您好我正在使用flask-sqlalchemy在烧瓶中进行一个小预测游戏我有一个用户模型:

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    nick = db.Column(db.String(255), unique=True)
    bets = relationship('Bet', backref=backref("user"))

和我的投注模型

class Bet(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    uid = db.Column(db.Integer, db.ForeignKey('user.id'))
    matchid = db.Column(db.Integer, db.ForeignKey('match.id'))
    points = db.Column(db.Integer)

两者都不是完整的类,但它应该为问题做。用户可以收集用于预测匹配结果的点,并获得用于预测确切结果,获胜者或差异的不同点数。 我现在想要一个顶级用户列表,我必须总结我正在做的点

toplist = db.session.query(User.nick, func.sum(Bet.points)).\
    join(User.bets).group_by(Bet.uid).order_by(func.sum(Bet.points).desc()).all()

这很有效,现在可能有两个玩家拥有相同点数的情况。在这种情况下,正确预测的数量(奖励3分)将定义胜利者。我可以通过

获取此列表
tophits = db.session.query(User.nick, func.count(Bet.points)).\
            join(User.bets).filter_by(points=3).all()

它们都运行良好,但我认为必须有一种方法可以将两个查询放在一起,并获得一个包含用户名,积分和“hitcount”的表格。我之前在SQL中已经完成了这项工作,但我并不熟悉SQLAlchemy,并且认为我脑子里有结。如何将两个查询合二为一?

1 个答案:

答案 0 :(得分:9)

tophits的查询中,只需将COUNT/filter_by构造替换为不含SUM(CASE(..))的等效filter,以便两者的WHERE子句相同。下面的代码应该这样做:

total_points = func.sum(Bet.points).label("total_points")
total_hits = func.sum(case(value=Bet.points, whens={3: 1}, else_=0)).label("total_hits")
q = (session.query(
        User.nick,
        total_points,
        total_hits,
        )
    .join(User.bets)
    .group_by(User.nick)
    .order_by(total_points.desc())
    .order_by(total_hits.desc())
    )

请注意,我更改了一个group_by子句以使用SELECT中的列,因为某些数据库引擎可能会抱怨。但你不需要这样做。