2014-01-18 14 views
2

我創建了具有列分數和排名的模型用戶。我想定期更新User中所有用戶的排名,使得得分最高的用戶排名第一,排名第二的排名第二等等。有沒有辦法在Flask-SQLAlchemy中有效實現這一點?如何使用sqlalchemy對條目進行排名?

謝謝!

順便說一句,這裏是模型:

app = Flask(__name__) 
db = SQLAlchemy(app)   
class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    score = db.Column(db.Integer) 
    rank = db.Column(db.Integer) 
+0

你爲什麼需要這些信息存儲在數據庫中,如果讓所有用戶的排名可以在SQL查詢本身可以實現大多數RDBMS。你使用哪個數據庫後端? – van

回答

0

只是週期上的所有用戶:

users = User.query.order_by(User.score._desc()).all() #fetch them all in one query 
for (rank, user) in enumerate(users): 
    user.rank = rank + 1 #plus 1 cause enumerate starts from zero 

db.session.commit() 
+0

不是有用的。有數千用戶的桌子怎麼樣? – SBillion

+0

@SBillion可能對大數據集沒有表現力,但說「無用」是一個錯誤。我的回答是純粹的sqlalchemy,因爲OP沒有指定他正在使用哪個rdbms。所以我們不能假定支持子查詢(就像上面的偉大zzzeek答案)。 在現代,您甚至可以使用跨處理器的多處理或任務隊列來分配這樣的任務,而不會阻止數據塊進行簡單的更新。 –

3

那麼遠,爲什麼一個可能做到這一點,它是如此,你可以查詢「排名「而不需要執行聚合查詢,這可以是更高性能的。特別是如果你想看到「用戶#456的排名是什麼?」沒有擊中每一行。

執行此操作的最有效方法是單個UPDATE。使用標準的SQL,我們可以使用相關子查詢是這樣的:

UPDATE user SET rank=(SELECT count(*) FROM user AS u1 WHERE u1.score > user.score) + 1 

有些數據庫有一個像PG的UPDATE..FROM,我有經驗較少,也許擴展,如果你能UPDATE..FROM的SELECT語句雖然我不完全確定,但使用更高效的窗口函數立即獲得排名。

反正我們與SQLAlchemy的標準SQL的樣子:

from sqlalchemy.orm import aliased 
from sqlalchemy import func 
u1 = aliased(User) 
subq = session.query(func.count(u1.id)).filter(u1.score > User.score).as_scalar() 
session.query(User).update({"rank": subq + 1}, synchronize_session=False) 
+0

正如@zzzeek所提到的,如果後端支持'UPDATE..FROM'和窗口函數,那麼可能會有更高效的方法。在PostgreSQL的情況下,你可以使用'ROW_NUMBER()'(檢查:http://www.postgresql.org/docs/9.3/static/functions-window.html)。 – yoloseem

相關問題