Skip to content
Advertisement

Count number of students above and below the average score in SQL

I have a sample table below and I am trying to get the number of student above the average score and number of students below the average score.

name    subject classroom   classarm    session     first_term_score    first_term_grade
std1    math    nursery 1A  nursery1    2018/2019     90                 A
std2    eng     nursery 1A  nursery1    2018/2019     70                 A
std3    sci     nursery 1A  nursery1    2018/2019     60                 B
std1    eng     nursery 1A  nursery1    2018/2019     64                 B
std2    math    nursery 1A  nursery1    2018/2019     70                 A

The target result table is supposed to look like

subject   avg_score count_above   count_below
math         80      1                1
eng          65.5    2                0

I have been able to write a query to get the names of students above the average score and this can be easily edited to get the count of students below the avg score.

SELECT name 
    FROM (SELECT name,
                 AVG(first_term_score) AS average_result
          FROM seveig
          GROUP BY name) sa, 
         (SELECT (AVG(first_term_score)) tavg
          FROM seveig) ta
     WHERE sa.average_result > ta.tavg

The issue here is that I want to add the counts in a table indicating the number of students above and below the average score.

If a number is equal to the average score, it can be considered as above the average score.

Advertisement

Answer

If you are running MySQL 8.0, you can use window functions and aggregation:

select
    subject,
    avg_score,
    sum(first_term_score >= avg_score) count_above,
    sum(first_term_score <  avg_score) count_below
from (
    select t.*, avg(first_term_score) over(partition by subject) avg_score
    from mytable t
) t
group by subject, avg_score

In earlier versions, you can join the table with an aggregate query that computes the average score per subject:

select
    t.subject,
    a.avg_score,
    sum(t.first_term_score >= a.avg_score) count_above,
    sum(t.first_term_score <  a.avg_score) count_below
from mytable t
inner join (
    select subject, avg(first_term_score) avg_score
    from mytable
    group by subject
) a on a.subject = t.subject
group by t.subject, a.avg_score

Edit: you appear to be running Big Query, not MySQL as initially tagged. You can use COUNTIF():

select
    subject,
    avg_score,
    countif(first_term_score >= avg_score) count_above,
    countif(first_term_score <  avg_score) count_below
from (
    select t.*, avg(first_term_score) over(partition by subject) avg_score
    from mytable t
) t
group by subject, avg_score
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement