从Oracle中的两个表中选择一条记录

时间:2012-05-26 18:12:38

标签: sql oracle11g greatest-n-per-group

有三个表格:

  1. 关于学生的表:s41071030(sno, sname, ssex, sage, sdept)

  2. 关于课程的表格:c41071030(cno, cname, cpno, credit)

  3. 关于选择课程的表格:sc41071030(sno, cno, grade)

  4. 现在,我想要选择sdept='CS'和他或她选择了部门'CS'中课程最多的学生的详细信息。

2 个答案:

答案 0 :(得分:1)

与任何适度复杂的SQL语句一样,最好做“TDQD” - 测试驱动的查询设计。从问题的简单部分开始,将它们构建成更复杂的答案。

要了解CS部门每个学生的课程数量,我们写道:

SELECT S.Sno, COUNT(*) NumCourses
  FROM s41071030 S
  JOIN sc41071030 SC ON S.Sno = SC.Sno
 WHERE S.Sdept = 'CS'
 GROUP BY S.Sno;

我们现在需要找到NumCourses的最大值:

SELECT MAX(NumCourses) MaxCourses
  FROM (SELECT S.Sno, COUNT(*) NumCourses
          FROM s41071030 S
          JOIN sc41071030 SC ON S.Sno = SC.Sno
         WHERE S.Sdept = 'CS'
         GROUP BY S.Sno
       )

现在我们需要将该结果与子查询相结合,因此是时候进行CTE(公用表表达式)了:

WITH N AS
    (SELECT S.Sno, COUNT(*) NumCourses
       FROM s41071030 S
       JOIN sc41071030 SC ON S.Sno = SC.Sno
      WHERE S.Sdept = 'CS'
      GROUP BY S.Sno
    )
SELECT N.Sno
  FROM N
  JOIN (SELECT MAX(NumCourses) MaxCourses FROM N) M
    ON M.MaxCourses = N.NumCourses;

我们需要获取学生的详细信息,因此我们将其加入学生表:

WITH N AS
    (SELECT S.Sno, COUNT(*) NumCourses
       FROM s41071030 S
       JOIN sc41071030 SC ON S.Sno = SC.Sno
      WHERE S.Sdept = 'CS'
      GROUP BY S.Sno
    )
SELECT S.*
  FROM s41071030 S
  JOIN N ON N.Sno = S.Sno
  JOIN (SELECT MAX(NumCourses) MaxCourses FROM N) M
    ON M.MaxCourses = N.NumCourses;

轻度测试的SQL:你被警告了。要进行测试,请运行组件查询,确保每次都能获得合理的结果。在上一个查询正常工作之前,请不要继续下一个查询。

请注意,课程表对您正在解决的查询并不重要。

另请注意,如果有几个学生都参加相同数量的课程,这可能会返回几行,而且这个数字是学生所服用的最大数字。 (因此,如果有3名学生各自参加7门课程,并且没有学生参加7门以上的课程,那么您将在结果集中看到3行。)

答案 1 :(得分:1)

  1. 汇总sc41071030行以获取计数。

  2. 将结果加入s41071030

    • 过滤sdept;

    • 上的行
    • 获取学生详细信息;

    • RANK()计数值上的已加入行。

  3. 选择排名为1的行。

  4. WITH
      aggregated AS (
        SELECT
          sno,
          COUNT(*) AS coursecount
        FROM
          sc41071030
        GROUP BY
          sno
      ),
      ranked AS (
        SELECT
          s.*,
          RANK() OVER (ORDER BY agg.coursecount DESC) AS rnk
        FROM
          s41071030 s
          INNER JOIN aggregated agg ON s.sno = agg.sno
        WHERE
          s.sdept = 'CS'
      )
    SELECT
      sno,
      sname,
      ssex,
      sage,
      sdept
    FROM
      ranked
    WHERE
      rnk = 1
    ;