MySQL - 计算多种条件下学生的排名

时间:2013-06-14 05:30:13

标签: mysql

我很抱歉,但标题有点误导。假设我有以下表格

-- user_tests table
Name                    |   Type
------------------------|----------------
id                      |   int(11)
user_id                 |   int(11)
test_schedule_id        |   int(11)
device_user_test_id     |   varchar(255)
time_taken              |   int(11)
total_marks             |   int(11)
total_questions         |   int(11)
attempt_count           |   int(11)
created_at              |   datetime
updated_at              |   datetime
-- user_test_questions table
Name                    |   Type
------------------------|-------------
id                  |   int
user_test_id            |   int
time_taken              |   int
marks_obtained          |   int
question_id             |   int
is_correct              |   enum
test_section_id         |   int
created_at              |   datetime
updated_at              |   datetime

user_tests表中的数据是参加test_schedule_id确定的特定考试的学生列表。每个test_schedule_id都有一个或多个test_section_id

我正在尝试按以下条件计算学生的等级:

  1. 根据test_schedule_id
  2. 的学生总分数获取排名
  3. 如果先前案例的排名相同,请在test_section_id = 1
  4. 上获得排名
  5. 如果先前案例的排名相同,请在test_section_id = 2
  6. 上获得排名
  7. 如果先前案例的排名相同,请在test_section_id = 3
  8. 上获得排名
  9. 如果之前案例的排名相同,请在用户出生日期(用户表格中)获取排名
  10. 我可以在Rails(或任何框架)中轻松完成它们,但我想避免它并使用ViewStored Procedure在SQL中解决它。

    现在我知道如何单独计算排名,但我正在努力结合这些条件。有没有办法做到这一点?我只是缺少MS SQL Server Rank()函数,我猜!

    谢谢

    修改:根据total_marks表格中user_tests的{​​{1}}表中的SUM(marks_obtained)排名。

1 个答案:

答案 0 :(得分:1)

让mysql完成它的工作是个好主意 - 所有连接和排序类型的东西。

我会选择类似的东西:

SELECT u.id AS uid, 
  SUM( utq.marks_obtained ) AS total_marks,
  SUM( (utq.test_section_id = 1)*utq.marks_obtained ) AS section1_marks,
  SUM( (utq.test_section_id = 2)*utq.marks_obtained ) AS section2_marks,
  SUM( (utq.test_section_id = 3)*utq.marks_obtained ) AS section3_marks,
  u.birthdate
FROM user_test_questions utq
JOIN user_tests ut ON ut.id = utq.user_test_id
JOIN users u ON u.id = ut.user_id
WHERE ut.test_schedule_id = 1
GROUP BY utq.user_test_id, u.id, u.birthdate
ORDER BY total_marks DESC, section1_marks DESC, section2_marks DESC, section3_marks DESC, u.birthdate

计算每个部分标记的技巧是将marks_obtained与boolean(test_section_id = 1)相乘,对于test_section_id = 1的行为1,对于其他部分为0,依此类推。

在GROUP BY中,您会看到三列符合sql标准,但您也可以尝试在那里看到utq.user_test_id,因为其他列在每个组中都具有相同的值。

对于test_schedule_id具有高度选择性的条件(你应该明确索引它)并且参加每个测试的学生不多(最多可能是数百个),这个查询应该是即时的,因为所有的排序都将在一个非常小的临时表上完成。 / p>