我有一个带测验的MySQL表,以及一个存储这些测验结果的表。结果行具有用户ID,测验ID,(编辑:时间戳)和数字分数。用户可以多次参加测验,但我们只计算他们第一次参加每个测验。
我正在尝试进行一个查询,告诉我每个用户出现在测验的前10位中的次数(假设测验已关闭),并将这些用户按他们进入的次数排名那个范围。这将允许我根据他们的完成情况显示所有时间排名。
关于我如何做到这一点的任何想法?
以下是架构的相关部分。
测验:
用户:
测验结果:
我的第一次尝试是这样的:
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名中的次数时,我意识到我的方向完全是错误的。我有点超出了我的联盟。 ,此时(设计师,这里)。
答案 0 :(得分: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
这还不足以取得"前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
我们现在可以将这组第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
非常可怕,是吗?