我有以下sqlalchemy查询:
score = Scores.query.group_by(Scores.email).order_by(Scores.date).subquery()
students = db.session.query(Students, score.c.id).filter_by(archive=0).order_by(Students.exam_date).outerjoin(score, Students.email == score.c.email)
然后我用以下内容渲染:
return render_template('students.html', students=students.all())
现在,问题在于我希望显示学生的最后得分,因为其中有许多对应于每个用户。但第一个似乎被退回了。我在第一次查询时尝试了一些排序和order_by,得分,但没有成功。
如何影响并选择“得分”中的最新结果与“学生”中的相应行配对?
谢谢!
答案 0 :(得分:2)
首先,您要确保子查询仅选择特定学生的行。您可以使用correlate
方法执行此操作:
score = db.session.query(Scores.id).order_by(Scores.date.desc()).correlate(Students)
由于您没有访问学生,因此无所事事。 correlate
的想法是,如果您在子查询中使用Students
,它将不将其添加到FROM
列表中,而是依赖于外部查询提供它。现在,您需要优化查询(如果您愿意,可以使用连接条件):
score = score.filter(Students.email == Scores.email)
这将产生一个子查询,每次只返回一个学生的分数。剩下的问题是,如果每个学生都有多个分数。如果是这样,你需要限制它(如果没有,你也不需要上面的order_by
部分):
score = score.limit(1)
现在您已确保查询返回单个标量值。由于您在选择上下文中使用查询,因此您需要将其转换为标量值:
students = db.session.query(Students, score.as_scalar()).filter_by(archive=0).order_by(Students.exam_date)
as_scalar
方法告诉SQLAlchemy这会返回单行和列。因为否则你无法将它放入选择中。
注意:如果您放置limit
,我并非100%确定您需要as_scalar
。尝试一下,然后到期。如果每个学生只有一个分数,那么你根本不需要担心任何这些东西。
有点暗示:Query
实例本身就是一个可迭代的。这意味着只要您不打印或类似,您就可以传递一个查询,就像一个列表一样,唯一的例外就是只能在访问(懒惰)上运行,并且您可以动态地优化它,例如您可以对其进行切片:students[:10]
只会选择前10个学生(如果您在查询中执行此操作,则会将其作为LIMIT
执行而不是切片列表,前者更有效)。