GROUP BY的局限性

yav*_*voh 5 sql oracle greatest-n-per-group

免责声明:我是一个SQL新手,这是一个类,但我真的可以使用正确的方向戳.

我有这三张桌子:

student(_sid_, sname, sex, age, year, gpa)
section(_dname_, _cno_, _sectno_, pname)
enroll(_sid_, grade, _dname_, _cno_, _sectno_)
(由下划线表示的主键)

我正在尝试编写一个与Oracle兼容的SQL查询,该查询返回一个表,其中包含学生姓名(student.sname),每个部分中包含最高gpa(包括section.cnosection.sectno),以及来自的所有其他属性section.

我设法使用聚合查询并GROUP BY获得每个部分的最大GPA:

  SELECT MAX(s.gpa), e.cno, e.sectno  
    FROM enroll e, 
         student s  
   WHERE s.sid = e.sid  
GROUP BY e.cno, e.sectno
Run Code Online (Sandbox Code Playgroud)

更别说其他section属性,我甚至无法弄清楚如何处理学生姓名(student.sname).如果我将它添加到SELECT子句中,则必须将其包含在GROUP BY其中弄乱查询的其余部分.如果我在外部查询的WHEREor FROM子句中使用这个整个查询,我只能访问表中的三个字段,这没有多大用处.

我知道你不能给我确切的答案,但任何提示都将不胜感激!

OMG*_*ies 3

假设使用 Oracle 9i+,要仅获取 GPA 最高的学生之一(如果出现平局),请使用:

WITH summary AS (
   SELECT e.*,
          s.name,
          ROW_NUMBER() OVER(PARTITION BY e.cno, e.sectno
                                ORDER BY s.gpa DESC) AS rank
     FROM ENROLL e
     JOIN STUDENT s ON s.sid = e.sid)
SELECT s.*
  FROM summary s
 WHERE s.rank = 1
Run Code Online (Sandbox Code Playgroud)

非 CTE 等效项:

SELECT s.*
  FROM (SELECT e.*,
               s.name,
               ROW_NUMBER() OVER(PARTITION BY e.cno, e.sectno
                                     ORDER BY s.gpa DESC) AS rank
          FROM ENROLL e
          JOIN STUDENT s ON s.sid = e.sid) s
 WHERE s.rank = 1
Run Code Online (Sandbox Code Playgroud)

如果您想查看所有 GPA 并列的学生,请使用:

WITH summary AS (
   SELECT e.*,
          s.name,
          DENSE_RANK OVER(PARTITION BY e.cno, e.sectno
                              ORDER BY s.gpa DESC) AS rank
     FROM ENROLL e
     JOIN STUDENT s ON s.sid = e.sid)
SELECT s.*
  FROM summary s
 WHERE s.rank = 1
Run Code Online (Sandbox Code Playgroud)