如何编写一个SQL查询来检索最近得分子集的高分 - 请参阅解释

时间:2011-01-19 20:29:32

标签: sql ranking

给出一个包含列的响应表:

用户名,LessonNumber,QuestionNumber,响应,得分,时间戳

我如何运行一个查询,返回哪些用户在过去5课中的每个问题首次尝试时得分为90分或更高? “最后5节课”是一个限制条件,而不是一个要求,所以如果他们完全只有1节课,但是他们首先尝试了每个问题,那么它们应该包括在结果中。我们只是不想回顾5课程。

关于数据:用户可能正在上不同的课程。有些用户可能还没有完成五节课(例如可能仅在第三课)。每节课都有不同数量的问题。用户有不同的课程路径,因此他们可能会跳过一些课程编号,甚至不按顺序完成课程。

由于这似乎是将时间上不均匀/不连续的值转换为每用户的统一/连续值的问题,我认为我可以通过几个排名函数调用来解决大部分问题。对于“在过去5课中每次问题的第一次尝试”得分超过90的条件规范也很棘手,因为完成的问题数量是每用户可变的。

到目前为止......

作为可能需要发生的事情的起点或暗示,我通过使用“row_number()over(按用户名分区,LessonNumber,按时间戳排序的问题编号)”将时间戳转换为每个问题的“尝试号”。 AttemptNumber”。

我还尝试将LessonNumber从绝对值转换为单个用户的连续排名值。我可以使用“dense_rank()over(按照LessonNumber desc的用户名顺序划分)作为LessonRank”,但是假设订单课程已完成,则与LessonNumber的顺序相对应,但遗憾的是并非总是如此。但是,让我们假设是这种情况,因为我确实有一种通过几个连接产生这样一个数字的方法,所以我可以使用描述的dense_rank变换来选择“最后5个已完成的课程”(即LessonRank< = 5)。

对于> 90条件,我想我可以将分数转换为整数,使得如果> = 90则为“1”,如果< = 0则为“0”。 90.然后,我可以引入类似“按用户名分组(分数)= COUNT(分数)。”的条款,它将仅选择所有分数等于1的用户。

任何解决方案或建议都将不胜感激。

3 个答案:

答案 0 :(得分:0)

随机建议:

1

  

对于“过去5节课中每个问题的第一次尝试”得分超过90的条件规范也很棘手,因为问题的数量是每用户可变的。

相当于

  

没有第一次尝试得分< = 90最近的5课程

让我觉得用NOT EXISTS子查询更容易抓住。

2

首次尝试与where timestamp = (select min(timestamp) ... )

相同

答案 1 :(得分:0)

您需要首先确定每个用户的前5个课程,使用时间戳来确定课程的优先级,然后您可以按分数进行限制。尝试:

Select username
from table t inner join
(select top 5 username, lessonNumber
 from table
 order by timestamp desc) l 
on t.username = l.username and t.lessonNumber = l.lessonNumber
from table
where score >= 90

答案 2 :(得分:0)

你有点放弃了解决方案:

SELECT DISTINCT Username
FROM Results 
WHERE Username NOT in (
    SELECT DISTINCT Username
    FROM (
        SELECT
            r.Username,r.LessonNumber, r.QuestionNumber, r.Score, r.Timestamp
            , row_number() over (partition by r.Username,r.LessonNumber,r.QuestionNumber order by r.Timestamp) as AttemptNumber
            , dense_rank() over (partition by r.Username order by r.LessonNumber desc) AS LessonRank
        FROM Results r
        ) as f
    WHERE LessonRank <= 5 and AttemptNumber = 1 and Score < 90
)

关于LessonRank,我使用了你所描述的内容,因为不清楚如何订购课程:第一次尝试课程的第一次尝试的时间戳?或者任何课程问题第一次尝试的时间戳?或者只是课程问题的任何结果的第一个(或最近的?)时间戳?

最里面的Select会添加您提供的所有AttemptNumberLessonRank

下一个Select仅保留会使用户无法进入最终列表的结果 - 所有在过去5课程中得分不足的首次尝试。我们最终会得到一个用户列表 not 想要在最终结果中显示。

因此,在最外面的Select,我们可以在排除列表中选择的所有用户。基本上所有其他用户都回答了任何问题。

编辑:经常,第二次尝试应该更好......

再多编辑

这是一个版本,包括评论中的评论。

SELECT Username
FROM 
(
    SELECT Username, CASE WHEN Score >= 90 THEN 1 ELSE 0 END AS QuestionScoredWell
    FROM (
        SELECT
            r.Username,r.LessonNumber, r.QuestionNumber, r.Score, r.Timestamp
            , row_number() over (partition by r.Username,r.LessonNumber,r.QuestionNumber order by r.Timestamp) as AttemptNumber
            , dense_rank() over (partition by r.Username order by r.LessonNumber desc) AS LessonRank
        FROM Results r
        ) as f
    WHERE LessonRank <= 5 and AttemptNumber = 1
) as ff
Group BY Username
HAVING MIN(QuestionScoredWell) = 1

我在计算出的Having值上使用MIN子句和QuestionScoredWell表达式。

在比较两个查询的执行计划时,此查询实际上更快。不确定这是否部分是由于我的表中数据行数量较少。