2012-04-20 3 views
1

J'essaie de faire une liste d'étudiants et leur efficacité avec des tests. Dans MySql base de données Je tablesRequête MySql - compter les lignes et les pourcentages

users - table avec les étudiants

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

courses - table avec des cours

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

questions - table avec des questions pour chaque cours. cours_id Row indique dans quel cours cette question appartient à

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 - chaque étudiant reçoit une invitation pour un cours. Row user_id affiche l'identifiant de l'utilisateur invité à suivre un cours. cours_id représente l'identifiant du cours qu'un étudiant doit faire. Lorsque l'état de la ligne a la valeur 0, cela signifie qu'un étudiant n'a pas commencé le cours (en cours) et s'il a la valeur 1, cela signifie que l'étudiant l'a démarré (ou terminé).

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 

Exemple: Joe et Anna sont invités à faire cours 1 et 2 Cours, Marry et Max sont invités à le faire seul cours 1. Joe a cours 1 mais pas Cours 2, Marry ne rien faire et Max a suivi le cours 1

courses_stats - sont les statistiques des questions des cours que les étudiants ont faites. Le statut représente l'exactitude de la réponse. 0 signifie mauvaise réponse et 1 pour corriger.

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 

Exemple: Joe a 3 questions de la première course.Notice qu'il n'a pas fait toutes les questions de ce cours et que l'on est incorrect.

Max a fait toutes les bonnes questions et Anna fait question d'abord (la moitié sont incorrectes) et la moitié du deuxième cours (tout correct)

je besoin d'une requête avec des noms de sudents, perecentage de cours finis, pourcentage des réponses correctes de ces cours qu'ils ont fait (pas tous les cours) et la possibilité de commander des étudiants par ces pourcentages. Quelque chose comme ceci:

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

est quelque chose comme ça possible? Ai-je besoin de plus de lignes dans les tableaux pour cette requête?

Répondre

4

Je pense que cela devrait être ce dont vous avez besoin: Comme une question de nouveau à vous

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 

, pourquoi les noms de table appelés cours_* plutôt que course_*?

+0

réponse rapide et belle requête. –

+0

Merci. L'original était légèrement faux. A besoin de 'LEFT JOIN 'comme vous le mentionnez dans votre réponse mais aussi une partie supplémentaire sur le' ON' pour s'assurer qu'il ne compte que des questions pour les cours que l'utilisateur a commencé (par exemple, les questions complétées de Joe doivent être 50%, pas 25% – MichaelRushton

+0

parfait, vous avez raison. vous voudrez peut-être ajouter 'ifnull (..., 0) AS completed_questions' car la question concurrente de marry sera nulle sinon, en lui montrant que 0 pourrait être meilleur. –

4

Ici vous pouvez trouver avec des schémas de table et des exemples de données, et le résultat de la requête. MichaelRushton a une réponse parfaite mais course_stats doit être LEFT rejoindre je pense. Parce que si l'étudiant a cours_invitations mais pas de course_stats, cette requête ne retournera pas cet utilisateur.

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 

Résultat:

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

Je suppose que vous vouliez dire "pourcentage de réponses correctes". OK, avec une construction intelligente de count(distinct if(..)) vous pouvez éviter les sous-requêtes complexes avec différentes clauses group-by. Par exemple, ce code

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

compte le nombre de questions (distinctes) lorsque la condition est remplie cours_invitations.status and courses_stats.status. En utilisant cette astuce, toute requête est aussi simple et élégante que celle-ci:

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 

Je recommande d'ajouter le signe de pourcentage en dehors mysql car il est beaucoup plus élégant là, il ajouterait la complexité uneccessary à la requête MySQL.

Questions connexes