Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Calculate 2 average values based on the same column, with different conditions

I have the following tables:

Students (id, name, surname, study_year, department_id)

Courses(id, name)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Course_Signup(id, student_id, course_id, year)

Grades(signup_id, grade_type, mark, date), where grade_type can be ‘e’ (exam), ‘l’ (lab) or ‘p’ (project)

I want to display the average grade at the exam and the lab+project, for each student.

SELECT new_table.id, new_table.name, new_table.grade_type, AVG(new_table.mark) AS "Average Exam Grade"
FROM (
    SELECT s.id, c.name, g.grade_type, g.mark
    FROM Students s
    JOIN Course_Signup csn
        ON s.id = csn.student_id
    JOIN Courses c
        ON c.id = csn.course_id
    JOIN Grades g
        ON g.signup_id = csn.id
) new_table
GROUP BY new_table.id, new_table.name, new_table.grade_type
HAVING new_table.grade_type = 'e'
ORDER BY new_table.id ASC

This will give me the average exam grade for each student, for every course they signed up for, but I want to also have an AVG(new_table.mark) AS "Average Activity Grade" which would be calculated based on the marks present in columns with grade_type = 'l' or grade_type = 'p'. Since I already have the exam grades condition in HAVING, how can I add the second condition for the second AVG?

>Solution :

Apply the filter inside the AVG() using CASE expressions.

SELECT
  new_table.id,
  new_table.name,
  AVG(CASE WHEN grade_type  = 'e' THEN new_table.mark END) AS "Average Exam Grade",
  AVG(CASE WHEN grade_type <> 'e' THEN new_table.mark END) AS "Average Activity Grade" 
FROM
(
  SELECT s.id, c.name, g.grade_type, g.mark
    FROM Students s
    JOIN Course_Signup csn
         ON s.id = csn.student_id
    JOIN Courses c
         ON c.id = csn.course_id
    JOIN Grades g
         ON g.signup_id = csn.id
)
  new_table
WHERE
  new_table.grade_type IN ('e', 'l', 'p')
GROUP BY
  new_table.id,
  new_table.name
ORDER BY
  new_table.id ASC

This works because…

  • CASE returns NULL (in the absences of an ELSE block) if not matched.
  • Aggregates (such as AVG()) skip / ignore NULL values.

Note; there’s no need for your sub-query, I left it in because you had it, but it is certainly redundant.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading