【问题标题】:Get top results for each group (in Oracle)获得每个组的最佳结果(在 Oracle 中)
【发布时间】:2010-09-13 04:38:14
【问题描述】:

我怎样才能在几个组中获得 N 个结果 一个预言机查询。

例如,给定下表:

|--------+------------+------------|
| emp_id | name       | occupation |
|--------+------------+------------|
|      1 | John Smith | Accountant |
|      2 | Jane Doe   | Engineer   |
|      3 | Jack Black | Funnyman   |
|--------+------------+------------|

有更多的行有更多的职业。我想得到 每个职业的三名员工(比方说)。

有没有办法在不使用子查询的情况下做到这一点?

【问题讨论】:

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


【解决方案1】:

我不确定这是否非常有效,但也许是一个起点?

select *
from people p1
    join people p2
        on p1.occupation = p2.occupation
    join people p3
        on p1.occupation = p3.occupation
        and p2.occupation = p3.occupation
where p1.emp_id != p2.emp_id
    and p1.emp_id != p3.emp_id

这应该为您提供包含 3 名不同员工的行,这些员工都在同一职业中。不幸的是,它会给你这些的所有组合。

有人能把这个删减吗?

【讨论】:

    【解决方案2】:

    我现在手头没有 oracle 实例,所以我没有对此进行测试:

    select *
    from (select emp_id, name, occupation,
          rank() over ( partition by occupation order by emp_id) rank
          from employee)
    where rank <= 3
    

    这是一个关于排名如何运作的链接:http://www.psoug.org/reference/rank.html

    【讨论】:

    • 他没有指定子查询吗...?
    • 是的,但他的意思很可能是“不使用再次从同一个表中选择的子查询”。此解决方案使用子查询,但只访问表一次。
    • 效果很好,似乎也依赖于数据库。
    【解决方案3】:

    在 SQL Server 中对此进行了测试(并且它使用子查询)

    select emp_id, name, occupation
    from employees t1
    where emp_id IN (select top 3 emp_id from employees t2 where t2.occupation = t1.occupation)
    

    只需在子查询中执行 ORDER 即可满足您的需求

    【讨论】:

      【解决方案4】:

      这会产生您想要的东西,并且它不使用特定于供应商的 SQL 功能,例如 TOP N 或 RANK()。

      SELECT MAX(e.name) AS name, MAX(e.occupation) AS occupation 
      FROM emp e 
        LEFT OUTER JOIN emp e2 
          ON (e.occupation = e2.occupation AND e.emp_id <= e2.emp_id) 
      GROUP BY e.emp_id 
      HAVING COUNT(*) <= 3 
      ORDER BY occupation;
      

      在本例中,它给出了每个职业中 emp_id 值最低的三名员工。您可以更改不等式比较中使用的属性,使其按姓名或其他方式提供顶级员工。

      【讨论】:

      • @codemon2002,使用 jop 在此线程上发布的答案。在 Oracle 中,您可以使用专门用于此类查询的窗口函数。
      • @MT0 - 我已经编辑了解决这些问题的答案。
      【解决方案5】:

      将 RowNum 添加到排名:

      select * from 
               (select emp_id, name, occupation,rank() over ( partition by occupation order by emp_id,RowNum) rank   
                            from employee) 
               where rank <= 3 
      

      【讨论】:

        猜你喜欢
        • 2020-03-25
        • 1970-01-01
        • 2017-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-22
        • 2011-01-08
        相关资源
        最近更新 更多