簡體   English   中英

SQLAlchemy過濾相關對象的查詢

[英]SQLAlchemy filter query by related object

使用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()  

我知道這顯然不正確,這只是我最好的猜測。 但是,在查看文檔和谷歌搜索后,我找不到答案。

編輯:如果我勾勒出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

單連接行方式,為所有用戶列添加了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))

上面兩個的效率很低,因為你在“用戶”的所有列上進行分組(或者你只使用MySQL的“幾列上的組”,這只是MySQL)。 為了最小化,子查詢方法:

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教程中: http//docs.sqlalchemy.org/en/latest/orm/tutorial.html#selecting-entities-from-subqueries

您需要使用子查詢來計算每個用戶的總分。 子查詢在此處描述: http ://www.sqlalchemy.org/docs/05/ormtutorial.html?highlight = subquery #using -subqueries

我假設您用於連接的列(不是關系)稱為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())

希望有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM