sql - 在 SQL 中使用 max()

标签 sql database select

我的家庭作业的一部分是从每个系中找出平均分最高的学生。

查询:

SELECT g.sid as studentID, s.sfirstname, s.dcode, AVG(grade) as average
FROM studentgrades g, student s
WHERE g.sid = s.sid
GROUP BY s.sid

结果:

1   Robert  ger 80.0000
2   Julie   sta 77.0000
3   Michael csc 84.0000
4   Julia   csc 100.0000
5   Patric  csc 86.0000
6   Jill    sta 74.5000

为了回答这个问题,我运行了查询

SELECT dcode, averages.sfirstName, MAX(averages.average)
FROM (
    SELECT g.sid as studentID, s.sfirstname, s.dcode, AVG(grade) as average
    FROM studentgrades g, student s
    WHERE g.sid = s.sid
    GROUP BY s.sid) averages
GROUP BY dcode

结果:

csc Michael 100.0000
ger Robert  80.0000
sta Julie   77.0000

即使平均值是正确的,但名称却不正确! Julia 是 csc 平均分 100 的人,那么为什么 Michael 会出现?


这是一个例子:

学生参加类(class)并获得这些类(class)的成绩。例如:

student1 from dept1 took course A and got grade 80
student1 from dept1 took course B and got grade 90
student2 from dept1 took course C and got grade 100
student3 from dept2 took course X and got grade 90

运行第一个查询后,我们得到每个学生的平均值

student 1 from dept1 has average 85
student 2 from dept1 has average 100
student 3 from dept2 has average 90

现在我们从每个系中找出平均分最高的学生

dept1, student2, 100
dept2, student3, 90

最佳答案

应该这样做(并且它根据 SQL 标准使用 GROUP BY,而不是 MySQL 实现它的方式)

select s.sid,
       s.sfirstname,
       s.dcode,
       ag.avg_grade
from students s
  join (select sid, avg(grade) as avg_grade
        from studentgrades 
        group by sid) ag on ag.sid = s.sid
  join (select s.dcode,
               max(avg_grade) max_avg_grade
        from students s 
          join (select sid, avg(grade) as avg_grade
                from studentgrades 
                group by sid) ag on ag.sid = s.sid
        group by s.dcode) mag on mag.dcode = s.dcode and mag.max_avg_grade = ag.avg_grade
order by mag.avg_grade;

这是如何运作的

这将分几步构建结果。首先它计算每个学生的平均成绩:

select sid, avg(grade) as avg_grade
from studentgrades 
group by sid

根据这个语句的结果,我们可以计算出最大值。平均成绩:

select s.dcode,
       max(avg_grade) max_avg_grade
from students s 
  join (select sid, avg(grade) as avg_grade
        from studentgrades 
        group by sid) ag on ag.sid = s.sid
group by s.dcode

现在这两个结果已连接到学生表中。为了便于阅读,假设有一个名为 average_grades(第一个语句)和 max_average_grades(第二个语句)的 View 。

最后的声明基本上是这样做的:

select s.sid,
       s.sfirstname,
       s.dcode,
       ag.avg_grade
from students s
  join avg_grades ag on ag.sid = s.sid
  join max_avg_grades mag 
    on mag.dcode = s.dcode 
   and mag.max_avg_grade = ag.avg_grade;

真正的(我回答中的第一个)只是将名称 avg_gradesmax_avg_grades 替换为我显示的选择。这就是它看起来如此复杂的原因。

可读性更好的标准 SQL 解决方案

在标准 SQL 中,这可以使用公共(public)表表达式来表达,这使得它更具可读性(但本质上是一样的)

with avg_grades (sid, avg_grade) as (
  select sid, avg(grade) as avg_grade
  from studentgrades 
  group by sid
), 
max_avg_grades (dcode, max_avg_grade) as (
  select s.dcode, max(avg_grade) max_avg_grade
  from students s 
     join avg_grades ag on ag.sid = s.sid
  group by s.dcode
)
select s.sid,
       s.sfirstname,
       s.dcode,
       ag.avg_grade
from students s
  join avg_grades ag on ag.sid = s.sid
  join max_avg_grades mag on mag.dcode = s.dcode and mag.max_avg_grade = ag.avg_grade;

但 MySQL 是极少数不支持此功能的 DBMS 之一,因此您需要坚持最初的声明。

需要较少派生表的标准 SQL 解决方案

在标准 SQL 中,使用窗口函数可以将其编写得更短一些以计算部门内的排名(同样这在 MySQL 中不起作用)

with avg_grades (sid, avg_grade) as (
  select sid, avg(grade) as avg_grade
  from studentgrades 
  group by sid
)
select sid, 
       sfirstname,
       dcode,
       avg_grade
from (       
  select s.sid,
         s.sfirstname,
         s.dcode,
         ag.avg_grade,
         rank() over (partition by s.dcode order by ag.avg_grade desc) as rnk
  from students s
    join avg_grades ag on ag.sid = s.sid
) t
where rnk = 1;

关于sql - 在 SQL 中使用 max(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13217069/

相关文章:

database - 存储和检索多个头像图像尺寸

mysql创建数据库名称错误

mysql select 同一列出现两次,但where子句不同

MySql 选择两个变量

mysql - 在 2 个表中选择匹配的字符串

php - mysql + php 检索带路径的叶子节点

sql - 如何运行多个 SQL 查询?

sql - 如何检查特定表上是否启用了更改跟踪

mysql - SQL 查询以连接结果中的列

c# - 来自 textBox 的值没有被插入到数据库中