如何从表中提取第二高行[重复]

Posted

技术标签:

【中文标题】如何从表中提取第二高行[重复]【英文标题】:How to extract second highest row from a table [duplicate] 【发布时间】:2016-01-27 15:15:03 【问题描述】:

我有四张桌子:

    批次(batch_id,batch_start_date,batch_strength,course_id) 课程(course_id、course_name、course_category、course_fees、course_duration) 注册(batch_id、student_id、注册日期) 学生(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 ;

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

【问题讨论】:

【参考方案1】:

使用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()

【讨论】:

@sagi 但 Gordon 指出,对于 tie 的情况,它也可以轻松更改为 dense_rank(),更不用说这是一种可移植的方法。 @sagi 你不能使用 rownum 除非你返回 1 和所需行号之间的每一行。请改用row_numberdense_rank 分析函数【参考方案2】:

非解析解只是为了好玩:

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 分组。这看起来更像是一个课堂练习,所以我不希望有任何复杂性,如历史费用信息或类似的事情。

编辑 根据您在下面的评论,听起来您可能有多个名称相同但费用不同的课程。我怀疑您的原始查询将无法正常工作,因为您也在 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))

【讨论】:

我打算在这里按 course_name 分组,因为 course_id 在这里无关紧要,不会产生正确的结果 @user5451270 course_id 似乎是您的主键。通常,您不希望按名称值分组。虽然我认为这里所有的课程名称都是独一无二的,但我认为这是一个坏习惯(除非你真的需要),并且在课堂之外使用主键可能对数据库引擎更有效率。如果您不介意分享,我很好奇它如何不能给出正确的结果。 当我按course_id 分组时,它不会像我预期的那样计算总收入。例如,就像在course_name 下一样,2 sql server 显示为单独的收入90007000 而我只希望 1 sql server 显示为收入为16000 并且没有course_name 列不是唯一的跨度> @user5451270 我希望你能看看我的编辑。但是,如果您确实有多个课程行具有相同的名称和不同的费用,那么您原始查询中的分组是不正确的。 你确定我会查看你的编辑并尝试找出我是否有任何错误【参考方案3】:

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

【讨论】:

以上是关于如何从表中提取第二高行[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何从表中删除重复值 [重复]

如何从表中删除重复记录? [复制]

如何从表中列出重复值? [复制]

选择查询以从表中查找重复值 [重复]

如何从表中一次选择相等的值[重复]

在Oracle中从表中删除重复行