MySQL用于计算用户拥有的前10个分数

时间:2015-09-11 20:49:30

标签: mysql sql

我有一个带测验的MySQL表,以及一个存储这些测验结果的表。结果行具有用户ID,测验ID,(编辑:时间戳)和数字分数。用户可以多次参加测验,但我们只计算他们第一次参加每个测验。

我正在尝试进行一个查询,告诉我每个用户出现在测验的前10位中的次数(假设测验已关闭),并将这些用户按他们进入的次数排名那个范围。这将允许我根据他们的完成情况显示所有时间排名。

关于我如何做到这一点的任何想法?

以下是架构的相关部分。

测验:

  1. ID
  2. 打开(时间戳)
  3. 关闭(时间戳)
  4. 用户:

    1. ID
    2. 电子邮件,姓名等作为个人资料信息
    3. 测验结果:

      1. ID
      2. 测验ID
      3. 用户ID
      4. 时间开始(时间戳)
      5. 时间结束(时间戳)
      6. 得分(整数)
      7. 我的第一次尝试是这样的:

        SELECT
        distinct least(user_id, time_end) as user_score, result_id, quiz_id, user_id, score, time_end - time_start as duration
        FROM results
        WHERE time_end != 0 AND user_id != 1 AND user_id != 0
        GROUP BY quiz_id, user_score
        ORDER BY user_id, time_end ASC;
        

        这有点帮助,但是当我意识到我需要用户出现在前10名中的次数时,我意识到我的方向完全是错误的。我有点超出了我的联盟。 ,此时(设计师,这里)。

1 个答案:

答案 0 :(得分:1)

  1. 首先,您需要确定每个用户在首次尝试时获得的分数。这是一个称为groupwise minimum的问题,只能通过查找每次首次尝试的(quiz, user, time)并将其加入results表来解决;然后可以对此结果集进行排序(通过测验和分数),以给出每个测验的首次尝试排名:

    SELECT   quiz_id, user_id, score
    FROM     results NATURAL JOIN (
               SELECT   quiz_id, user_id, MIN(time_end) time_end
               FROM     results
               WHERE    time_end > 0
               GROUP BY quiz_id, user_id
             ) firstAttempts
    ORDER BY quiz_id, score DESC
    
  2. 这还不足以取得"前10名"来自这些群体中的每个群体,因为多个用户可以分享第10个最高分 - 而且仅选择其中一些用户是不公平的。因此,我们必须找到第10个最高分,然后找到每个第一次尝试得分至少那么多的用户。

    不幸的是,MySQL不支持分析功能 - 因此没有一种简洁的方法来查找"第10条记录"来自每个小组。相反,我们可以使用其user-defined variables来计算排名,因为上面的结果集已生成,然后在外部查询中筛选所需的排名:

    SELECT quiz_id, score
    FROM   (
             SELECT   quiz_id, score,
                      @rank    := IF(quiz_id = @quiz_id, @rank + 1, 1) AS rank,
                      @quiz_id := quiz_id
             FROM     (SELECT @rank := NULL, @quiz_id := NULL) init,
                      results NATURAL JOIN (
                        SELECT   quiz_id, user_id, MIN(time_end) time_end
                        FROM     results
                        WHERE    time_end > 0
                        GROUP BY quiz_id, user_id
                      ) firstAttempts
             ORDER BY quiz_id, score DESC
           ) rankedFirstAttempts
    WHERE  rank = 10
    
  3. 我们现在可以将这组第10个最高分数加入到第一次尝试(我们可以再次生成,如上面的#1),然后按用户分组并按它们出现的次数排序:

    SELECT   user_id, COUNT(*) numberOfTimesInTop10
    FROM     results NATURAL JOIN (
               SELECT   quiz_id, user_id, MIN(time_end) time_end
               FROM     results
               WHERE    time_end > 0
               GROUP BY quiz_id, user_id
             ) firstAttempts JOIN (
               SELECT   quiz_id, score,
                        @rank    := IF(quiz_id = @quiz_id, @rank + 1, 1) AS rank,
                        @quiz_id := quiz_id
               FROM     (SELECT @rank := NULL, @quiz_id := NULL) init,
                        results NATURAL JOIN (
                          SELECT   quiz_id, user_id, MIN(time_end) time_end
                          FROM     results
                          WHERE    time_end > 0
                          GROUP BY quiz_id, user_id
                        ) firstAttempts
               ORDER BY quiz_id, score DESC
             ) rankedFirstAttempts
            ON rankedFirstAttempts.rank     = 10
           AND rankedFirstAttempts.quiz_id  = results.quiz_id
           AND rankedFirstAttempts.score   <= results.score
    GROUP BY user_id
    ORDER BY numberOfTimesInTop10 DESC
    
  4. 非常可怕,是吗?