【问题标题】:Get the top row after order by in Oracle Subquery在 Oracle 子查询中排序后获取第一行
【发布时间】:2010-08-03 06:30:36
【问题描述】:

我有一个表学生(id、姓名、部门、​​年龄、分数)。我想找到每个部门得分最高(在最年轻的学生中)的最年轻的学生。在 SQL Server 中,我可以使用以下 SQL。

select * from student s1 
where s1.id in 
(select s2.id from student s2 
where s2.department = s1.department order by age asc, score desc top 1).

但是,在 Oracle 中,您不能在子查询中使用 order by 子句,并且没有 limit/top like 关键字。我必须将学生表与自身连接两次才能查询结果。在 oracle 中,我使用以下 SQL。

select s1.* from student s1, 
(select s2.department, s2.age, max(s2.score) as max_score from student s2, 
(select s3.department, min(s3.age) as min_age from student s3 group by s3.department) tmp1 where 
s2.department = tmp1.department and s2.age = tmp1.min_age group by s2.department, s2.age) tmp2 
where s1.department =tmp2.department and s1.age = tmp2.age and s1.score=tmp2.max_score

有没有人想为oracle简化上面的SQL。

【问题讨论】:

  • 在 Oracle 中,您可以在子查询中使用 order by 子句。
  • 有一个更简单的解决方案,没有分析功能,请参阅我的问题的公认答案:stackoverflow.com/questions/38180445/…

标签: sql database oracle oracle10g limit


【解决方案1】:

试试这个

select * from
  (SELECT id, name, department, age, score,
  ROW_NUMBER() OVER (partition by department order by age desc, score asc) srlno 
  FROM student) 
where srlno = 1;

【讨论】:

  • 我有类似的情况,想用 pl/sql 块来处理,但你的解决方案效果很好!!
【解决方案2】:

除了 Bharat 的回答之外,还可以在 Oracle 的子查询中使用 ORDER BY 来执行此操作(正如 Jeffrey Kemp 所指出的那样):

SELECT *
FROM   student s1
WHERE  s1.id IN (SELECT id
                 FROM   (SELECT   id, ROWNUM AS rn
                         FROM     student s2
                         WHERE    s1.department = s2.department
                         ORDER BY age ASC, score DESC)
                 WHERE  rn = 1);

如果您使用此方法,您可能会想删除子查询而只使用rownum = 1。这将导致不正确的结果,因为排序将在条件之后应用(您会得到 1 行已排序,而不是排序集中的一行)。

【讨论】:

  • 问题其实是问“各部门”的第一行。您没有使用部门对结果进行分组。对于那些在不阅读问题内容的情况下查看与标题类似的问题的人来说,这个答案可能很有用。但我想指出人们比较解决方案的区别(因为他们不会得到相同的结果)。
【解决方案3】:

除了艾伦的回答,这也很好用:

select * 
from (SELECT * 
  FROM student
  order by age asc, 
           score desc) 
where rownum = 1;

【讨论】:

  • 这只会返回“所有”结果的第一行。这可能与问题标题相匹配。但问题实际上是问“每个部门”的第一行。这就是为什么它比 Bharat 的答案更简单。
  • 这是真的 Protron,我实际上错过了这个区别,并回答了一个更简单的问题,这实际上是我在谷歌搜索并找到此线程时正在寻找的内容。所以我想所有的答案都是正确和有用的,这取决于读者实际在寻找什么。为了我的目的,艾伦的答案是最有用的,然后我对其进行了改进并重新发布。出于您的目的,巴拉特的答案是最有用的。每个人都赢了! (虽然,我注意到艾伦根据您的提示编辑了他的答案,但我会保持原样,因为它对许多人来说是一个完美的答案)。
【解决方案4】:
select to_char(job_trigger_time,'mm-dd-yyyy') ,job_status from
(select * from kdyer.job_instances ji INNER JOIN kdyer.job_param_values pm 
on((ji.job_id = pm.job_id) and (ji.job_spec_id = '10003') and (pm.param_value='21692') )
order by ji.job_trigger_time desc)
where rownum<'2'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多