【问题标题】: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))。
  • 那么,是否要检索每个专业的高年级学生?
  • 不对。已编辑。

标签: mysql sql inner-join average greatest-n-per-group


【解决方案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

【讨论】:

【解决方案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 在这种情况下你会期待什么?
  • 只选择其中任何一个,好像学生信息无关紧要,查询是“按职业划分的平均成绩更高”,无论哪个学生。
  • 好吧,就是这样! :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多