MySql查询 - 计算行和百分比

时间:2012-04-20 09:47:21

标签: mysql count left-join percentage cross-join

我正在尝试通过测试列出学生及其效率。 在MySql数据库中我有表

users - 与学生同桌

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

courses - 包含课程的表

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

questions - 每个课程都有问题的表格。 Row 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

示例: Joe和Anna被邀请参加课程1和课程2,Marry和Max被邀请只参加课程1. Joe做了课程1而不是课程2,Marry没有做任何事情和马克斯都做了课程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

示例: Joe在第一期课程中提出了3个问题。通知他没有完成该课程的所有问题而且该课程不正确。

Max确实所有的问题都是正确的,Anna在第一道菜上做了所有问题(一半是不正确的),一半来自第二道菜(都是正确的)

我需要一个查询,包括名字,完成课程的百分比,他们所做的那些课程的正确答案的百分比(不是所有课程)以及按这些百分比命令学生的可能性。 像这样:

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

这样的事情是否可能?我是否需要在表中为此查询添加更多行?

3 个答案:

答案 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_*

答案 1 :(得分:4)

在这里您可以找到表格模式和示例数据以及查询结果。 MichaelRushton有完美的答案,但我认为course_stats必须是LEFT join。 因为如果学生有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

答案 2 :(得分:0)

我猜你的意思是“正确答案的百分比”。好的,通过巧妙地使用count(distinct if(..))构造,您可以避免使用具有不同分组子句的复杂子查询。例如,此代码

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之外添加百分号,因为它在那里更加优雅,它会给mysql查询增加不必要的复杂性。