各专业平均成绩较高的学生

Posted

技术标签:

【中文标题】各专业平均成绩较高的学生【英文标题】:Student with greater average grades by major 【发布时间】:2021-01-16 09:09:55 【问题描述】:

表格和数据:

CREATE TABLE major
( 
    id INT PRIMARY KEY, 
    name VARCHAR(200)
);

insert into major values 
    (101, 'Computing'), 
    (102, 'Arquitecture');

CREATE TABLE student
( 
    id INT PRIMARY KEY, 
    name VARCHAR(200), 
    major_id INT,
    foreign key(major_id) references major(id)
);

insert into student  values
    (1001, 'Claude', 101),
    (1002, 'John', 101),
    (1003, 'Peter', 102);

CREATE TABLE course
( 
    id INT PRIMARY KEY, 
    name VARCHAR(200)
);

insert into course values 
    (901, 'Databases'), 
    (902, 'Java'),
    (903, 'Artificial Intelligence'), 
    (904, 'OOP');
    
CREATE TABLE grades
(
   student_id INT,
   course_id INT,
   grade integer,
   primary key (student_id, course_id),
   foreign key(student_id) references student(id),
   foreign key(course_id) references course(id)
);

insert into grades  values
    (1001, 903, 95),
    (1001, 904, 88),
    (1002, 901, 76),
    (1002, 903, 82),
    (1003, 902, 87);

预期:

| student    | major        | grade |
| ---------- | -------------| ----- |
| Peter      | Architecture | 87    |
| Claude     | Computing    | 91.5  |

换句话说:检索每个专业的高年级学生。

游乐场here.

如果可能,不带 TOP,LIMIT。

如果可能的话,使用旧的 ANSI SQL 以及使用窗口函数。

引擎 mysql,但不是必需的。

我的做法#1:

-- average grade by student
select s.name as Student,  m.name as Major, avg(g.grade) as Average
         from student s
         inner join grades g on (s.id = g.student_id)
         inner join major m on (m.id = s.major_id)
         group by s.id

但不需要约翰:

| Student | Major        | Average |
| ------- | ------------ | ------- |
| Claude  | Computing    | 91.5000 |
| John    | Computing    | 79.0000 |
| Peter   | Arquitecture | 87.0000 |

我的做法#2:

-- Max average grade by career; lacks student
select a.major, max (a.average) as Average
    from (select s.name as Student,  m.name as Major, avg(g.grade) as average
         from student s
         inner join grades g on (s.id = g.student_id)
         inner join major m on (m.id = s.major_id)
         group by s.id) a
    group by a.major;           

但缺少学生栏。

| major        | Average |
| ------------ | ------- |
| Arquitecture | 87.0000 |
| Computing    | 91.5000 |

谢谢。

【问题讨论】:

排除约翰的标准是什么? @ntalbs John 正在学习计算,但 Cluade 的平均成绩更高。必须按专业分组,然后选择平均分较高的学生,例如 max(avg(grade))。 那么,是否要检索每个专业的高年级学生? 不对。已编辑。 【参考方案1】:

如果您运行的是 MySQL 8.0,您可以使用rank()

select *
from (
    select s.name as student, m.name as major, avg(g.grade) as average,
        rank() over(partition by m.id order by avg(g.grade) desc) rn
    from student s
    inner join grades g on s.id = g.student_id
    inner join major m on  m.id = s.major_id
    group by s.id, m.id
) t
where rn = 1

注意事项:

rank() 允许绑定

连接条件的括号是多余的

【讨论】:

如果克劳德和约翰的平均成绩相同怎么办? db-fiddle.com/f/3mr4GRz5tJ3ofFeQcTZvF8/7 @Antoniosánchez:正如我所说,rank() 允许平局,所以它给了 Claude 和 John。你想要哪个结果? 只选择其中任何一个,好像学生信息无关紧要,查询是“按职业划分的平均成绩更高”,无论哪个学生。 @AntonioSánchez:如果是这样,请使用row_number() 而不是rank()【参考方案2】:

你可以结合你的两个查询:

select a.* FROM 
(        select s.name as Student, m.name as Major, avg(g.grade) as Average
         from student s
         inner join grades g on (s.id = g.student_id)
         inner join major m on (m.id = s.major_id)
         group by s.id
) a
INNER JOIN 
(select a.major, max (a.average) as Average
    from (select s.name as Student,  m.name as Major, avg(g.grade) as average
         from student s
         inner join grades g on (s.id = g.student_id)
         inner join major m on (m.id = s.major_id)
         group by s.id) a
    group by a.major   ) b
ON a.major=b.major and a.average=b.average

【讨论】:

一般来说,SELECT 子句中的所有非聚合列都必须包含在 GROUP BY 子句中——尽管我接受学生只能拥有一个专业的前提。 如果克劳德和约翰的平均成绩相同怎么办? db-fiddle.com/f/3mr4GRz5tJ3ofFeQcTZvF8/6 那你要么需要使用top,要么切换到window函数。 GMB 已经使用窗口函数提供了答案db-fiddle.com/f/cABESz8puGeFSfGfAytPtu/0【参考方案3】:

对于旧版本的 MySQL...

SELECT x.* 
  FROM
     ( SELECT m.name major
            , s.name student
            , AVG(grade) avg_grade
         FROM major m
         JOIN student s
           ON s.major_id = m.id
         JOIN grades g
           ON g.student_id = s.id
        GROUP
           BY major
            , student
     ) x
  JOIN
     (
       SELECT major
            , MAX(avg_grade) avg_grade
         FROM 
            ( SELECT m.name major
                   , s.name student
                   , AVG(grade) avg_grade
                FROM major m
                JOIN student s
                  ON s.major_id = m.id
                JOIN grades g
                  ON g.student_id = s.id
               GROUP
                  BY major
                   , student
            )n
        GROUP
           BY major
      ) y
     ON y.major = x.major
    AND y.avg_grade = x.avg_grade

| major        | student | avg_grade |
| ------------ | ------- | --------- |
| Arquitecture | Peter   | 87.0000   |
| Computing    | Claude  | 91.5000   |

---

View on DB Fiddle

【讨论】:

如果克劳德和约翰的平均成绩相同怎么办? db-fiddle.com/f/3mr4GRz5tJ3ofFeQcTZvF8/8 @AntonioSánchez 在这种情况下你会期待什么? 只选择其中任何一个,好像学生信息无关紧要,查询是“按职业划分的平均成绩更高”,无论哪个学生。 好吧,就是这样! :-)

以上是关于各专业平均成绩较高的学生的主要内容,如果未能解决你的问题,请参考以下文章

输入两个学生的学号姓名和成绩,输出成绩较高的学生的学号姓名和成绩

输入两个学生的学号姓名和成绩,输出成绩较高的学生的学号姓名和成绩

Hive 基础测试

sql练习

学生成绩管理程序

sql计算机系的平均成绩为多少?