2012-04-20 67 views
1

我试图列出学生及其测试效率。 在MySql数据库我有表MySql查询 - 计算行数和百分比

users - 表与学生

id | name 
_________ 
1 | Joe 
2 | Marry 
3 | Max 
4 | Anna 
---------- 

courses - 表课程

id | name 
_____________ 
1 | Course 1 
2 | Course 2 
---------- 

questions - 以每门课程的问题表。行cours_id表示这当然这个问题属于

id | cours_id | question 
_________________________________ 
1 | 1  | Course 1 - question 1 
2 | 1  | Course 1 - question 2 
3 | 1  | Course 1 - question 3 
4 | 1  | Course 1 - question 4 
5 | 2  | Course 2 - question 1 
6 | 2  | Course 2 - question 2 
7 | 2  | Course 2 - question 3 
8 | 2  | Course 2 - question 4 

cours_invitations - 每个学生得到邀请为一疗程。行user_id显示被邀请参加课程的用户的ID。 cours_id代表学生应该做的课程的ID。 当行状态的值为0时,表示学生没有开始课程(待定),如果它的值为1,表示学生已经开始(或完成)。

id | user_id | cours_id | status 
________________________________ 
1 | 1  | 1  | 1 
2 | 1  | 2  | 0 
3 | 2  | 1  | 0 
4 | 3  | 1  | 1 
5 | 4  | 1  | 1 
6 | 4  | 2  | 1 

例子:乔和安娜被邀请做课程1和课程2,结婚和Max被邀请做唯一的办法1.乔做了场1,但当然不是2,结婚没做什么和马克思课程1

courses_stats - 是学生已经完成的课程的问题的统计数字。状态代表答案的准确性。 0代表错误答案,1代表正确答案。

id | user_id | question_id | status 

___________________________________ 
1 | 1  | 1   | 1 
2 | 1  | 2   | 1 
3 | 1  | 3   | 0 
4 | 2  | 1   | 1 
5 | 2  | 2   | 1 
6 | 2  | 3   | 1 
7 | 2  | 4   | 1 
8 | 4  | 1   | 1 
9 | 4  | 2   | 1 
10 | 4  | 3   | 0 
11 | 4  | 4   | 0 
12 | 4  | 5   | 1 
13 | 4  | 6   | 1 

例子:乔的确从他并没有这样做从该课程所有问题的第一course.Notice 3个问题,那种是不正确。

马克斯做了所有的问题,正确的和安娜做了所有的问题,从第一场(一半是不正确的),另一半来自第二期培训班(正确)

我需要sudents名称,成品课程perecentage,百分比查询他们所做的那些课程的正确答案(并非全部课程)以及按这些百分比命令学生的可能性。 事情是这样的:

name | completed courses | completed questions 
______________________________________________ 
Max |100%    |100% 
Anna |100%    |50% 
Joe |50%    |50% 
Marry |0%     |0% 

是这样甚至可能吗?这个查询在表格中是否需要更多行?

回答

4

我想这应该是你所需要的:

SELECT 
    users.name, 
    CONCAT(COUNT(
     DISTINCT CASE 
     WHEN cours_invitations.status = 1 THEN 
      cours_invitations.id 
     ELSE 
      NULL 
     END 
    )/COUNT(
     DISTINCT cours_invitations.id 
    ) * 100, '%') AS completed_courses, 
    CONCAT(COUNT(
     DISTINCT CASE 
     WHEN courses_stats.status = 1 THEN 
      courses_stats.id 
     ELSE 
      NULL 
     END 
    )/COUNT(DISTINCT questions.id) * 100, '%') AS completed_questions 
FROM 
    users 
LEFT JOIN cours_invitations ON cours_invitations.user_id = users.id 
LEFT JOIN questions ON cours_invitations.cours_id = questions.cours_id 
AND cours_invitations.status = 1 
LEFT JOIN courses_stats ON users.id = courses_stats.user_id 
GROUP BY 
    users.id 
ORDER BY 
    completed_courses DESC, 
    completed_questions DESC 

作为一个问题丢回给你,为什么表名叫做cours_*而非course_*

+0

快速的答案和很好的查询。 – 2012-04-22 15:08:20

+0

谢谢。原来有点不对。需要'LEFT JOIN's就像你在你的答案何况还要对'ON'一个额外的一部分,以确保其只计算用户已经开始的课程(例如问题,Joe的完成问题,需要为50%,而不是25% ) – MichaelRushton 2012-04-22 15:15:19

+0

完美,你是对的。你可能想添加'ifnull(...,0)AS completed_questions',因为结婚的竞争问题将为空,否则显示0可能会更好。 – 2012-04-22 15:28:59

4

在这里你可以找到表模式和样本数据,以及查询结果。 MichaelRushton有完美的答案,但我认为course_stats必须是左连接。 因为如果学生有cours_invitations但没有course_stats,则该查询不会返回该用户。

http://sqlfiddle.com/#!2/019dc/1

SELECT 
    users.name, 
    COUNT(
     DISTINCT CASE 
     WHEN course_invitations.status = 1 THEN 
      course_invitations.id 
     ELSE 
      NULL 
     END 
    )/COUNT(
     DISTINCT course_invitations.id 
    ) * 100 AS completed_courses, 
    COUNT(
     DISTINCT CASE 
     WHEN courses_stats.status = 1 THEN 
      courses_stats.id 
     ELSE 
      NULL 
     END 
    )/COUNT(DISTINCT questions.id) * 100 AS completed_questions 
FROM users 
INNER JOIN course_invitations ON course_invitations.user_id = users.id 
INNER JOIN questions ON course_invitations.cours_id = questions.cours_id 
LEFT JOIN courses_stats ON users.id = courses_stats.user_id 
GROUP BY 
    users.id 

结果:

NAME COMPLETED_COURSES COMPLETED_QUESTIONS 
Joe 50 25 
Marry 0 100 
Max 100 0 
Anna 100 50 
0

我猜你的意思是 “正确答案的百分比”。好吧,巧妙地使用count(distinct if(..))结构,您可以避免使用不同的group-by子句进行复杂的子查询。例如,该代码

count(distinct if(cours_invitations.status and courses_stats.status, 
         NULL, questions.id)) 

计数,其中条件cours_invitations.status and courses_stats.status被满足的(不同)问题的数量。使用这一招,整个查询是简单而优雅的,因为这:

select users.name, 
    count(distinct if(cours_invitations.status, 
         NULL, 
         cours_invitations.cours_id)) 
     /count(distinct cours_invitations.cours_id) 
     * 100 as courses_completed, 
    count(distinct if(cours_invitations.status and courses_stats.status, 
          NULL, 
          questions.id)) 
     /count(distinct if(cours_invitations.status, 
           NULL, 
           questions.id)) 
     * 100 as correct_answers 
from users 
    left join cours_invitations on users.id = cours_invitations.user_id 
    left join questions using (cours_id) 
    left join courses_stats on users.id = courses_stats.user_id 
           and questions.id = courses_stats.question_id 
group by users.id 
order by correct_answers 

我建议增加外的MySQL百分号,因为它是更优雅那里,这会增加uneccessary复杂MySQL查询。