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, e.g. 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).
Related
I apply order_by to a queryset and the results are mixed up.
Is there any difference if I apply it to a queryset?
The table has three columns: Name Age Description
Here is the code:
Query = table1.objects.filter(Name__iexact='Nico').order_by('Age').distinct()
ages = Query.values_list('Age')
descr= Query.values_list('Description')
Here only Age is sorted correctly. The match between these Age and Description is distorted. What is wrong here?
What is wrong ? Well, actually, the design itself. "Parallel lists" - two lists (or similar types) matched on position - is an antipattern. It's bulky, harder to use (you have to keep track of indexes and subscript the two lists), and brittle (if anything changes one of the lists for whatever reason, the data are not matched anymore).
If you need to keep both informations matched, keep them in a single list (or here queryset) as tuples (here query.values_list("Age", "Description")) or dicts (here query.values("Age", "Description")). This will make your code simpler and safer.
NB: I of course assume you want to match those two querysets given your mention that "The match between these Age and Description is distorted".
Try to have your order_by on the end after distinct.
Either that or try
Query = table1.objects.filter(Name__iexact='Nico').distinct()
Query = Query.order_by('Age')
I have some Entry boxes on a form and a button that will search a db's table by executing a query that is composed of a WHERE clause with several conditions corresponding to the input boxes.
The user may or may not fill all the input boxes, so I just want to have a predefined query with all columns on the where clause like:
column01=? AND column02=? AND ... AND columnN=?
and then have a tuple or list which simply I have constructed on a loop where inputed data is placed on the same order, columns of the WHERE clause were arranged and each input only checked whether it was "" (not been input) and if so the respective place in the list would be assigned something that makes that specific condition transparent!. To clarify myself, see what means if user filled no input box (imagine that thing would be an asterisk):
"SELECT * FROM sometable WHERE column01=* AND ... AND columnN=*"
that is desirable to work like this query:
"SELECT * FROM sometable"
which bears no constrain on any column. Is this credible?
As Christos correctly pointed out above, pattern matching in SQL queries is the way to do this and lots of other much more complicated things.
I just need to use LIKE instead of equality sign and assign '%' to any condition I want to make transparent. more information here
I have a query which selects an entity A and some calculated fields
q = session.query(Recipe,func.avg(Recipe.somefield).join(.....)
I then use what I select in a way which assumes I can subscript result with "Recipe" string:
for entry in q.all():
recipe=entry.Recipe # Access KeyedTuple by Recipe attribute
...
Now I need to wrap my query in an additional select, say to filter by calculated field AVG:
q=q.subquery();
q=session.query(q).filter(q.c.avg_1 > 1)
And now I cannot access entry.Recipe anymore!
Is there a way to make SQLAlchemy adapt a query to an enclosing one, like aliased(adapt_on_names=True) orselect_from_entity()`?
I tried using those but was given an error
As Michael Bayer mentioned in a relevant Google Group thread, such adaptation is already done via Query.from_self() method. My problem was that in this case I didn't know how to refer a column which I want to filter on
This is due to the fact, that it is calculated i.e. there is no table to refer to!
I might resort to using literals(.filter('avg_1>10')), but 'd prefer to stay in the more ORM-style
So, this is what I came up with - an explicit column expression
row_number_column = func.row_number().over(
partition_by=Recipe.id
).label('row_number')
query = query.add_column(
row_number_column
)
query = query.from_self().filter(row_number_column == 1)
New to using Python NDB.
I have something like:
class User(ndb.Model):
seen_list = nbd.KeyProperty(kind=Survey, repeated=True)
class Survey(ndb.Model):
same = ndb.StringProperty(required=True)
I want to be able to query for users that have not seen certain surveys.
What I am doing now is:
users = User.query(seen_list != 'survey name').fetch()
This does not work. What would be the proper way to do this? Should I first query the Survey list to get the key of the survey with a certain name? Is the != part correct?
I could not find any examples similar to this.
Thanks.
unfortunately, if your survey is a repeated property, it won't work that way. When you query a repeated property the datastore tries EVERY entry in your list, and if one works, it'll return the item. So when you say "!= survey name 1", if you have at least ONE entry in your list that isn't "survey name 1", it'll come back as positive, even if another result IS "survey name 1".
it's uninstinctive if you come from an SQL background I know.... the only way to go around that is to go programatically and evaluate the ones your query returns. It comes from the fact that, for repeated values, Big Table "flatten" your results, which means it creates one entry for EVERY value in your repeated attribute. so as it scans, it eventually finds one "correct" line with your info, grabs the object key from there, and returns the object.
Say I run a query with a filter,
Session.query(model.Place).join(model.Location).filter(model.Location.great_circle_distance(location) < r)
In order to get the results of this query, it had to have calculated model.Location.great_circle_distance(location). After running this query, I can get a list of Places which match that criteron of having a great_circle_distance less than r, but, is there any way to return both the result of that calculation and the list of Places that match that query in one fell swoop?
You could use join, column_property and mapper to derive a class that is, essentially, a database view. But unless you intended to use that in more than one place, or the number of rows is huge, I would just do a separate query to get the Location objects and use map to compute the circle distances.