SQLAlchemy фильтруют запрос связанным объектом

Используя SQLAlchemy, у меня есть один многим отношение с двумя таблицами - пользователи и очки. Я пытаюсь запросить лучшие 10 пользователей, отсортированных по их совокупному счету по прошлому X сумм дней.

users:  
  id  
  user_name  
  score  

scores:  
  user   
  score_amount  
  created  

Мой текущий запрос:

 top_users = DBSession.query(User).options(eagerload('scores')).filter_by(User.scores.created > somedate).order_by(func.sum(User.scores).desc()).all()  

Я знаю, что это ясно не корректно, это - просто мое лучшее предположение. Однако после рассмотрения документации и поиска с помощью Google я не могу найти ответ.

Править: Возможно, помогло бы, делал ли я набросок того, на что был бы похож запрос MySQL:

SELECT user.*, SUM(scores.amount) as score_increase 
FROM user LEFT JOIN scores ON scores.user_id = user.user_id 
WITH scores.created_at > someday 
ORDER BY score_increase DESC

16
задан codeape 6 January 2014 в 20:03
поделиться

3 ответа

[

] Однослойный путь, с добавлением []group_by[] для всех пользовательских столбцов, хотя MySQL позволит вам группироваться только по столбцу "id", если вы выберете:[

] [
    sess.query(User, func.sum(Score.amount).label('score_increase')).\
               join(User.scores).\
               filter(Score.created_at > someday).\
               group_by(User).\
               order_by("score increase desc")
] [

]Или если вы просто хотите, чтобы пользователи в результате:[

] [
sess.query(User).\
           join(User.scores).\
           filter(Score.created_at > someday).\
           group_by(User).\
           order_by(func.sum(Score.amount))
] [

]Вышеуказанные два варианта неэффективны в том, что вы группируете по всем столбцам "user" (или вы используете MySQL's "группировать только по нескольким столбцам", который является только MySQL). Чтобы минимизировать это, в учебнике ORM используется подзапросный подход:[

] [
subq = sess.query(Score.user_id, func.sum(Score.amount).label('score_increase')).\
                  filter(Score.created_at > someday).\
                  group_by(Score.user_id).subquery()
sess.query(User).join((subq, subq.c.user_id==User.user_id)).order_by(subq.c.score_increase)
] [

]Пример идентичного сценария приведен в учебнике ORM at: []http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#selecting-entities-from-subqueries[][

]
21
ответ дан 30 November 2019 в 22:02
поделиться

Вам нужно будет использовать подзапрос, чтобы вычислить суммарную оценку для каждого пользователя. Подзапросы описаны здесь: http://www.sqlalchemy.org/docs/05/ormtutorial.html? highlight=subquery#using-subqueries

1
ответ дан 30 November 2019 в 22:02
поделиться

Я предполагаю, что столбец (не связь), который вы используете для соединения, называется Score.user_id, так что поменяйте его, если это не так.

Вам нужно будет сделать что-то вроде этого:

DBSession.query(Score.user_id, func.sum(Score.score_amount).label('total_score')).group_by(Score.user_id).filter(Score.created > somedate).order_by('total_score DESC')[:10]

Однако это приведет к кортежам (user_id, total_score). Я не уверен, действительно ли вычисленная оценка важна для вас, но если это так, вы, вероятно, захотите сделать что-то вроде этого:

users_scores = []
q = DBSession.query(Score.user_id, func.sum(Score.score_amount).label('total_score')).group_by(Score.user_id).filter(Score.created > somedate).order_by('total_score DESC')[:10]
for user_id, total_score in q:
    user = DBSession.query(User)
    users_scores.append((user, total_score))

Это приведет к тому, что будет выполнено 11 запросов. Все это можно сделать в одном запросе, но из-за различных ограничений в SQLAlchemy, это, скорее всего, создаст очень уродливый мульти-запрос или подзапрос (в зависимости от движка), и он будет не очень производительным.

Если вы планируете делать что-то подобное часто и у вас большое количество баллов, подумайте о денормализации текущей оценки в пользовательской таблице. Больше работы по обслуживанию, но это приведет к одному не соединенному запросу типа:

DBSession.query(User).order_by(User.computed_score.desc())

Надежда, что это поможет.

0
ответ дан 30 November 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: