【问题标题】:MySQL (JDBC) - Leaderboard ranking based on column valuesMySQL (JDBC) - 基于列值的排行榜排名
【发布时间】:2016-03-18 23:41:17
【问题描述】:

目标:

  • 查找由“viewedUserId”标识的给定用户的排名

排名:

  • 经验越高,等级越高(越低)。
  • 如果两个或更多用户具有相同的体验,则更好的排名将授予首先获得该体验的人。 (updated_at 列存储 currentTimeMillis (bigint/long))
  • 排名永远不应该打成平手。 (任何用户都不能拥有与其他用户相同的排名)

问题:

  • 是否可以计算查询中的排名,这样我们就不必手动循环并比较每个存储的用户的结果。 (理想情况下,我们希望返回 1 个带有排名的结果)

代码:

public static int getRank(Connection connection, int viewedUserId) throws SQLException {
    Statement statement = null;
    ResultSet resultSet = null;
    try {
        statement = connection.createStatement();
        resultSet = statement.executeQuery("SELECT user_id FROM scores ORDER BY experience DESC, updated_at ASC");
        int rank = 1;
        while(resultSet.next()) {
            int userId = resultSet.getInt("user_id");
            if(userId == viewedUserId)
                return rank;
            rank++;
        }
        throw new SQLException("Failed to find rank for user: " + viewedUserId);
    } finally {
        DatabaseUtils.close(statement, resultSet);
    }
}

关注:

  • 上面的代码将按照我的预期工作,但性能是一个主要因素。使用上述代码并不理想,因为我们的“分数”表将包含数十万行。

【问题讨论】:

    标签: mysql jdbc system ranking


    【解决方案1】:

    是的,您可以在查询中执行此操作。 MySQL 中最简单的方法是使用变量:

    SELECT s.user_id, (@rn := @rn + 1) as rank
    FROM scores s CROSS JOIN
         (SELECT @rn := 0) params
    ORDER BY s.experience DESC, s.updated_at ASC;
    

    几乎所有其他数据库都为此目的支持 ANSI 标准函数 row_number()rank()。此外,如果您有较大的数据,并且scores(experience, updated_at, user_id) 上的索引对于性能来说是最佳的。

    编辑:

    要获得特定用户的排名,最简单的方法是使用不带变量的查询:

    select count(*)
    from scores s cross join
         scores su
    where su.user_id = $user_id and
          (s.experience > su.experience or
           s.experience = su.experience and s.updated_at <= su.updated_at)
    

    【讨论】:

    • 我是否必须从这些结果中进行选择才能获得特定的用户排名?如果我在该查询中添加以下内容: WHERE s.user_id = 9017 排名为 1,这是不正确的。
    • @Wonderlus 。 . .这实际上是一个非常不同的问题,请参阅编辑后的回复。
    【解决方案2】:

    看这个问题:https://dba.stackexchange.com/questions/13703/get-the-rank-of-a-user-in-a-score-table

    他们有一张这样的桌子:

    Id  Name    Score
    1   Ida     100
    2   Boo     58
    3   Lala    88
    4   Bash    102
    5   Assem   99
    

    并添加排名:

    SELECT id, name, score, FIND_IN_SET( score, (
    SELECT GROUP_CONCAT( score
    ORDER BY score DESC ) 
    FROM scores )
    ) AS rank
    FROM scores
    

    导致

    id name  score rank
    1  Ida   100   2
    2  Boo    58   5
    3  Lala   88   4
    4  Bash  102   1
    5  Assem  99   3
    

    您还可以添加 WHERE 子句来过滤单个用户。

    【讨论】:

    • 谢谢。我确实看过那个帖子,但它似乎没有正确解释关系。
    • 那么您应该在 ORDER BY 子句中添加另一条语句,以便也根据另一列进行排序。
    猜你喜欢
    • 2018-01-31
    • 2012-09-08
    • 2019-02-14
    • 2015-01-29
    • 2020-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多