How to sort test score average of a class?

Discussion in 'MySQL' started by aayybb, Jan 20, 2010.

  1. #1
    Hi,

    The fields in the table class are student_name, test_score1, test_score2, test_score3.

    How do I have a result of listing of student_name, test_score1, test_score2, test_score3 and average_score in order that the highest average student shows on top?

    (There is no existing field for average in the table. If the student only took 2 test, the average will be total scores/ 2, not divided by 3.)

    I am guessing it will look like the following except I don't know how to get the count of test taken.

    select student_name, test_score1, test_score2, test_score3 from class order by (test_score1 + test_score2 + test_score3) / "count of test taken" DESC


    Thanks for any help in advance.
     
    Last edited: Jan 20, 2010
    aayybb, Jan 20, 2010 IP
  2. crivion

    crivion Notable Member

    Messages:
    1,669
    Likes Received:
    45
    Best Answers:
    0
    Trophy Points:
    210
    Digital Goods:
    3
    #2
    you need this directly into sql or php?
     
    crivion, Jan 20, 2010 IP
  3. koko5

    koko5 Active Member

    Messages:
    394
    Likes Received:
    14
    Best Answers:
    1
    Trophy Points:
    70
    #3
    Hi,
    I've tested this query and it works perfect :)
    
    SELECT student_name,
    test_score1,
    test_score2,
    test_score3,
    ((IF(test_score1 IS NULL,0,test_score1)+IF(test_score2 IS NULL,0,test_score2)+IF(test_score3 IS NULL,0,test_score3))/IF((IF(test_score1 IS NULL,0,1)+IF(test_score2 IS NULL,0,1)+IF(test_score3 IS NULL,0,1))=0,1,IF(test_score1 IS NULL,0,1)+IF(test_score2 IS NULL,0,1)+IF(test_score3 IS NULL,0,1))) average
    FROM class ORDER BY average DESC;
    
    Code (markup):
    Regards,
    Nick
     
    koko5, Jan 20, 2010 IP
  4. aayybb

    aayybb Peon

    Messages:
    128
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #4
    Nick,

    Thank you very much. I was confused with so many if in your code at first. I made it a bit simpler with your help and it works. Thanks again for the kind help.
     
    aayybb, Jan 21, 2010 IP
  5. plog

    plog Peon

    Messages:
    298
    Likes Received:
    11
    Best Answers:
    1
    Trophy Points:
    0
    #5
    If you plan on having any more quizzes I suggest you normalize your data. Look how long that conditional statement is in the query. And that's with just 3 quizzes. Its going to get burn-victim ugly really fast if you try and add any more quizzes to that table as fields.

    If you make a seperate table for quiz scores you can easily use the AVG function of mysql to do all that work for you.
     
    plog, Jan 21, 2010 IP
  6. jestep

    jestep Prominent Member

    Messages:
    3,659
    Likes Received:
    215
    Best Answers:
    19
    Trophy Points:
    330
    #6
    I was going to suggest the same thing. Storing data like this is called denormalization. It goes against the grain of how a database is designed to operate. There are a few cases where denormalization works, but this is not one of them.

    Ideally you want to have a student table, and then separately a test table, with a foreign key relation between the tests and students. You can then perform any sort of mathematical function based on specific tests, scores, dates, test numbers, or whatever else you need.
     
    jestep, Jan 21, 2010 IP
  7. koko5

    koko5 Active Member

    Messages:
    394
    Likes Received:
    14
    Best Answers:
    1
    Trophy Points:
    70
    #7
    @aayybb glad to help :) Hope that decreasing if statements will not cause division by zero in some cases (I didn't know can score fields be NULL or they have default value, so I've used so many IFs)!

    Sometimes denormalization is required to keep right the database normal form.

    Looking at table structure, I guess that student_name is primary/unique key, so there is no problem to use AVG function in virtual tables:
    
    SELECT t1.*,SCORE FROM class t1 NATURAL JOIN (
    SELECT student_name,AVG(score) SCORE FROM
    ((SELECT student_name,test_score1 score FROM class)
    UNION ALL
    (SELECT student_name,test_score2 FROM class)
    UNION ALL
    (SELECT student_name,test_score3 FROM class)
    ) A
    GROUP BY 1
    ORDER BY 2 DESC) B
    ORDER BY SCORE DESC;
    
    Code (markup):
    Best regards,
    Nick
     
    koko5, Jan 21, 2010 IP
  8. aayybb

    aayybb Peon

    Messages:
    128
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #8
    Any good mysql book (not too dry) to read?
     
    aayybb, Jan 27, 2010 IP
  9. koko5

    koko5 Active Member

    Messages:
    394
    Likes Received:
    14
    Best Answers:
    1
    Trophy Points:
    70
    #9
    Click me
    Regards,
    Nick
     
    koko5, Jan 27, 2010 IP