几个星期以来,我一直被相当著名的按年级排名学生的问题所困扰,虽然我学到了很多,但我仍然没有解决我的问题(排名已生成,但过程太慢) :
我有一个大表(320,000 行),其中包含学生代码(用作标识符,而不是他们的姓名)、学生课堂、测试、测试日期、主题、问题编号和学生对该问题的评分. 该表是计算其他所有内容的基础,它的大小使所有这些计算非常缓慢,以至于我发现我几乎在工作中破坏了这里的所有内容。
首先,一些关于学校的信息(非常少的信息,需要了解问题)
在学校,我们每周都会对几个科目进行测试。学校也有不同目的的教室(一个专注于数学、物理和化学,另一个专注于生物,最后一个专注于历史、葡萄牙语和地理)。但他们每周都做同样的测试。
我们要做的是计算学校每个人(不是每个教室)每个问题的标准差和每个问题的平均成绩(也适用于学校每个人),然后生成以下排名(所有这些都是日期):
- 每个教室的每门学科排名(带有“原始”成绩),考虑整个学校的每门学科排名(带有“原始”成绩)和考虑整个学校的每门学科排名(使用标准化成绩,每个问题的标准差和平均值每个问题信息的等级)
-与上面提到的相同的排名,但不是每个主题,而是考虑所有主题
可以看到,在计算了平均分和标准差之后,我们还需要计算每道题的总分,并根据这些总和(实际科目/考试成绩)进行排名。我已经通过几种方式解决了这个问题:
1) 创建了两个表,其中一个包含每个学生每个科目的成绩(字段:学生代码、学生课堂、考试日期、学科、成绩、标准化成绩、课堂排名、学校排名、使用标准化成绩的学校排名)和另一个是每个学生每次测试的成绩(所有科目都考虑在内,字段:学生代码、学生课堂、测试日期、成绩、标准化成绩、课堂排名、学校排名、使用标准化成绩的学校排名)。
在这些表中插入数据大约需要 50 秒
然后,我尝试使用 SQL 进行排名,但是,我遇到了一些问题:
-Access 没有 ROW_NUMBER 或 RANK 函数,因此我必须使用带有 COUNT 的查询,例如(以下只是一个简化版本):
SELECT 1+(SELECT Count(*) FROM grades_table_per_subject t2 WHERE
t2.Grade > t1.Grade AND t1.Date=t2.Date AND t1.Subject=t2.Subject) AS [Global Rank],
1+(SELECT Count(*) FROM grades_table_per_subject t3 WHERE t3.Grade > t1.Grade AND
t3.Date=t1.Date AND t3.Subject=t1.Subject AND t3.Classroom=t1.Classroom) AS
[Rank in classroom] FROM grades_table_per_subject;
上面的查询中还有归一化成绩的排名,但我省略了它。
表 grades_table_per_subject 有大约 45,000 行,这个查询在这里需要超过 15 分钟,即使有索引(尝试了许多不同的索引组合,当我看到应该工作的那些没有时,甚至是一些奇怪的组合)。
我还尝试对内部选择进行 ORDER BY Count( ) DESC 排序,但我在 7 分钟后按 ctrl+break 并没有结果。
2) 在上表中添加了以下字段:课堂排名、学校排名、使用标准化成绩的学校排名
然后我尝试使用带有 DAO 的 VBA 并手动更新排名字段,运行以下代码(简化版):
Set rs = CurrentDb.OpenRecordset("SELECT Classroom, Date, Subject, Grade, [Rank in classroom] FROM
grades_table_per_subject ORDER BY Date, Classroom, Subject, Grade DESC;", dbOpenDynaset)
...
...
rs.movefirst
i=1
While Not rs.eof
'Verifies if there was a change on either one of Subject, Classroom, Date and if so:
...
i = 1
...
rs.Edit
rs![Rank in classroom]=i
rs.Update
i = i + 1
rs.movenext
Wend
rs.close
这显然只建立了一个等级(在这种情况下,每个教室每个科目),并且只需要 3 分 10 秒。
我验证了由于表格上的写入,它需要很长时间(rs.Edit 和 rs.Update 是罪魁祸首,评论它们使整个事情在 4 秒内运行),但我需要写入表格来生成排名稍后访问报告。
最后:
我可以一次生成所有排名,并为用户提供快速访问所有数据的方法,但想法是所有内容都应该即时计算。然而,我们所取得的时间使这成为不可能。
总的来说,要问的问题如下: -
有没有办法在 10 秒内通过 Access Query 计算上面显示的排名,或者考虑到大小,使用 VBA 并在类似的时间内将这些排名插入到表中这里使用的表?
另外,我很想看到一个高效的排名算法列表,这样即使我不能快速完成所有事情,我也可以尽可能地改进它。