【问题标题】:How can I rank entries using sqlalchemy?如何使用 sqlalchemy 对条目进行排名?
【发布时间】:2014-02-08 00:49:12
【问题描述】:

我创建了一个模型用户,它具有列分数和排名。我想定期更新 User 中所有用户的排名,使得分最高的用户排名 1,得分第二高的排名 2,等等。有没有办法在 Flask-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)

【问题讨论】:

  • 如果大多数 RDBMS 上的 SQL 查询本身可以获取所有用户的排名,为什么还需要将其存储在数据库中。您使用哪个数据库后端?

标签: python sql sqlalchemy flask flask-sqlalchemy


【解决方案1】:

至于为什么要这样做,这样您就可以查询“排名”而无需执行聚合查询,这样可以提高性能。特别是如果您想查看“用户 #456 的排名是多少?”无需击中每一行。

最有效的方法是一次更新。使用标准 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)

【讨论】:

【解决方案2】:

只需循环访问所有用户:

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

【讨论】:

  • 没用。拥有数千名用户的表呢?
  • @SBillion 可能对大型数据集表现不佳,但说“没用”是错误的。我的答案是纯 sqlalchemy,因为 OP 没有指定他使用的是哪个 rdbms。所以我们不能假设支持子查询(就像上面的 zzzeek 回答一样)。而在现代,您甚至可以使用多处理或任务队列在工作人员之间分配这样的任务,而不会在微不足道的更新中阻塞数据库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 2022-08-23
相关资源
最近更新 更多