简体   繁体   中英

Order_by in sqlalchemy with outer join

I have the following sqlalchemy queries:

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)

And then I render the things with:

return render_template('students.html', students=students.all())

Now, the issue is that I want the last score for a student to be displayed, as there are many of them corresponding to each user. But the first one seems to be returned. I tried some sortings and order_by on the first query, score, but without success.

How can I affect and pick only one latest result from the "score" to be paired with the corresponding row in "students"?

Thanks!

First of all you want to make sure that the subquery selects only rows for a particular student. You do that with the correlate method:

score = db.session.query(Scores.id).order_by(Scores.date.desc()).correlate(Students)

This alone does nothing, as you do not access the students. The idea of correlate is that if you use Students on your subquery, it will not add it to the FROM list but instead rely on the outer query providing it. Now you will want to refine your query (the join condition if you wish):

score = score.filter(Students.email == Scores.email)

This will produce a subquery that each time only returns the score for a single student. The remaining question is, if each student has to multiple scores. If so, you need to limit it (if there isn't, you don't need the order_by part from above as well):

score = score.limit(1)

Now you have made sure your query returns a single scalar value. Since you are using the query in a select context you will want to turn it into a scalar value:

students = db.session.query(Students, score.as_scalar()).filter_by(archive=0).order_by(Students.exam_date)

The as_scalar method is a way of telling SQLAlchemy that this returns a single row and column . Because otherwise you could not put it into a select.

Note : I am not 100% sure you need that limit if you put as_scalar . Try it out and expirment. If each student has only one score anyway then you don't need to worry at all about any of that stuff.

A little hint on the way: A Query instance is by itself an iterable. That means as long as you don't print it or similar, you can pass around a query just like a list with the only exception that will really only run on access (lazy) and that you can dynamically refine it, eg you could slice it: students[:10] would only select the first 10 students (and if you do it on the query it will execute it as a LIMIT instead of slicing a list, where the former is much more efficient).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM