GROUP BY的局限性

时间:2010-10-14 02:45:19

标签: 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.cno和{{1} }}以及section.sectno的所有其他属性。

我设法使用汇总查询和section来获取每个部分的最大GPA:

GROUP BY

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

我知道你不能给我确切的答案,但任何提示都会受到赞赏!

6 个答案:

答案 0 :(得分: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

非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

如果您想查看所有与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

答案 1 :(得分:1)

提示:考虑到一个班级可能有不止一个GPA最高的学生。外部查询只需要三个字段。

答案 2 :(得分:0)

也许最短:

SELECT DISTINCT e.cno, e.sectno , e...,
       FIRST_VALUE(s.sname) OVER 
                              (PARTITION BY e.cno, e.sectno ORDER BY s.gpa DESC)
FROM enroll e, 
     student s  
WHERE s.sid = e.sid 

SELECT A.* 
FROM
    (  SELECT s._sid, s.sname, e.cno, e.sectno  ,..., s.gpa
              MAX(s.gpa) OVER (PARTITION BY e.cno, e.sectno) AS maxgpa
       FROM enroll e, 
            student s  
       WHERE s.sid = e.sid  
    ) A
WHERE A.maxgpa = A.gpa

答案 3 :(得分:0)

以下是一些指示: -

  1. 您使用Group By query
  2. 走在正确的轨道上
  3. 根据cno和sectno字段
  4. 返回每个部分的最大GPA
  5. 现在,您拥有每个cno和sectno组合的最大GPA值。
  6. 如果您想现在找到符合这些组合值的所有学生,请以相反的方式使用您拥有的这些数据。 提示:将Group By查询的结果视为表格并使用INNER JOIN
  7. 即使可能有超过1名学生获得相同的最高GPA,您仍然可以获得所有GPA
  8. 希望这会有所帮助!!

答案 4 :(得分:0)

这应该可以满足您的需求。有关GPA按部分从最高到最低排名的详细信息,请参阅Oracle的RANK()函数。

<强>要求:

返回一个表格,其中包含学生姓名(student.sname),每个部分中的gpa最高(section.cno和section.sectno)以及部分中的所有其他属性。

SELECT * FROM 
(
    SELECT 
        s.sname,
        s.gpa,
        sec.dname, 
        sec.cno, 
        sec.sectno,
        sec.pname,
        /* for each "sec.cno, sec.sectno", this will rank each GPA in order from highest to lowest. Ties will have the same rank. */
        RANK() OVER(PARTITION BY sec.cno, sec.sectno ORDER BY s.gpa DESC) as r_rank
    FROM
        enroll e, 
        student s,
        section sec
    WHERE 
        /* join enroll with student */
        s.sid = e.sid
        /* join section with enroll */
        AND sec.dname = e.dname
        AND sec.cno = e.cno
        AND sec.sectno = e.sectno
)
WHERE r_rank = 1  /* this returns only the highest GPA (maybe multiple students) for each "sec.cno, sec.sectno" combination */ 
;

注意:如果您不想要领带,请将RANK()更改为ROW_NUMBER()

答案 5 :(得分:0)

虽然很久以后就回答了这个问题,但我仍想提出一个beautiful explanation,这对新手来说非常有用。 Introduction to SQL也有这样的规则。