【问题标题】:MySql query - counting rows and percentagesMySql 查询 - 计算行数和百分比
【发布时间】:2012-05-01 21:32:26
【问题描述】:

我正在尝试列出学生及其考试效率。 在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

示例: Joe 和 Anna 被邀请参加课程 1 和课程 2,Marry 和 Max 被邀请只参加课程 1。Joe 参加了课程 1 但没有参加课程 2,Marry 没有参加任何事情,Max 做了课程 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%

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

【问题讨论】:

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


    【解决方案1】:

    我认为这应该是你需要的:

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

    【讨论】:

    • 谢谢。原文略有错误。需要LEFT JOINs,就像您在回答中提到的那样,还需要在ON 上添加一个额外的部分,以确保它只计算用户已经开始的课程的问题(例如,Joe 完成的问题需要是 50%,而不是 25%)
    • 完美,你是对的。您可能想添加ifnull(...,0) AS completed_questions,因为结婚的竞争问题将为空,否则显示为 0 可能会更好。
    • 我在想,但我不确定它是否适用。你不会因为没有参加考试而得到 0%(Marry 就是这种情况;请注意 0% 完成的课程)。也许是'N/A' 而不是NULL
    • 非常感谢。我在cours_* 上犯了一个错误,我会改正的。
    【解决方案2】:

    您可以在此处找到表架构和示例数据以及查询结果。 MichaelRushton 有完美的答案,但我认为 course_stats 必须是 LEFT 加入。 因为如果学生有 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
    

    【讨论】:

      【解决方案3】:

      我猜你的意思是“正确答案的百分比”。好的,通过巧妙地使用 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 之外添加百分号,因为那里更优雅,它会给 mysql 查询增加不必要的复杂性。

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 1970-01-01
        • 2014-04-06
        • 1970-01-01
        • 2017-10-17
        • 2013-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多