如何从 table 中提取第二高的行

How to extract second highest row from a table

我有四个 tables :

  1. 批处理(batch_id, batch_start_date, batch_strength, course_id)
  2. 课程([=3​​5=], course_name, course_category, course_fees, course_duration)
  3. 注册人数(batch_id, student_id, enrollment_date)
  4. 学生(student_id, student_name, student_mail, student_date_of_birth, student_city, student_phone, student_qualification)

现在根据问题我必须显示收入第二高的课程名称

根据上面的问题,这里是我的解决方案

select c.course_name, c.course_fees*count(c.course_name) Total_Revenue
from course c join(batch b join enrollment e 
on b.batch_id=e.batch_id) 
on c.course_id=b.course_id
group by c.course_name, c.course_fees
order by Total_Revenue desc ;

现在的问题是我无法从上述代码的结果 table 中提取第二行。如何从上面的结果 table 中提取第二行?(感谢特定于 Oracle 11g 的答案)

使用row_number():

select *
from (select c.course_name, c.course_fees*count(c.course_name) as Total_Revenue,
             row_number() over (order by c.course_fees*count(c.course_name)) as seqnum
      from batch b join
           enrollment e 
           on b.batch_id = e.batch_id join
           course c
           on c.course_id=b.course_id
      group by c.course_name, c.course_fees
     ) bec
where seqnum = 2;

如果您能获得并列第一但仍想获得第二名,请使用 dense_rank() 而不是 row_number()

您还可以创建自己的聚合函数。 Oracle docs 提到的函数SecondMax 为例。但是如果有一个合适的索引,那么 row_numer 函数可能会给出更好的执行计划。

Non-analytic 解决方案只是为了好玩:

with r as (
    select min(c.course_name) as course_name, min(c.course_fees) * count(*) as revenue
    from
        course c
        inner join batch b on b.course_id = c.course_id
        inner join enrollment e on e.batch_id = b.batch_id
    group by c.course_id
)
select course_name, revenue
from r
where revenue = (select max(revenue) from r where revenue < (select max(revenue) from r))

这会处理平局(第一和第二)。我也很谨慎,假设您真的打算按 course_id 分组。这看起来更像是一个 class 练习,所以我不希望有任何复杂的事情,比如历史费用信息或类似的事情。

编辑 根据您在下面的评论,听起来您可能有多个名称相同但费用不同的课程。我怀疑您的原始查询无法正常工作,因为您也在 course_fees.

上分组

请注意下面的更改使用了 course_name 上的分组和 course_fees 上的求和:

with r as (
    select course_name, sum(c.course_fees) as revenue
    from
        course c
        inner join batch b on b.course_id = c.course_id
        inner join enrollment e on e.batch_id = b.batch_id
    group by c.course_name
)
select course_name, revenue
from r
where revenue = (select max(revenue) from r where revenue < (select max(revenue) from r))