【问题标题】:How to Get Set of Second Highest Values?如何获得第二高值?
【发布时间】:2018-02-11 01:56:11
【问题描述】:

假设我有下表:

    employee_id    salary
    34             100
    22             49
    19             49
    29             30
    17             22

我想返回薪水第二高的员工集合(当有平局时),如下:

   employee_id    salary
   22             49
   19             49

我该怎么做?

【问题讨论】:

    标签: sql oracle top-n


    【解决方案1】:

    使用DENSE_RANK:

    SELECT employee_id, salary
    FROM
    (
        SELECT employee_id, salary, DENSE_RANK() OVER (ORDER BY salary DESC) dr
        FROM yourTable
    ) t
    WHERE dr = 2;
    

    【讨论】:

    • 没有意识到我可以在没有分区的情况下使用 DENSE_RANK() OVER。谢谢!
    • @ajf1000 - 这适用于大多数分析函数; “无分区”表示所有行都是单个分区的一部分。 (等效地,如果您想明确包含partition by,以向未来阅读代码的下一个开发人员表明您没有忘记它,您可以partition by null - 具有相同的效果,所有行都是单个分区。)
    【解决方案2】:

    您可以使用嵌套查询。

    采取的步骤:

    1. 获取所有工资值(排序并获得第二高的值):

    SELECT salary FROM employee GROUP BY 1 ORDER BY 1 DESC limit 1 OFFSET 1;

    OR 可以写成:

    SELECT salary FROM employee GROUP BY employee_id ORDER BY employee_id DESC limit 1 OFFSET 1;
    

    现在在员工表中使用查询

    SELECT * FROM employee where salary=(SELECT salary FROM employee GROUP BY 1 ORDER BY 1 DESC limit 1 OFFSET 1);

    【讨论】:

    • Oracle 不支持LIMIT;那是 MySQL 语法。
    • @TimBiegeleisen - Oracle 12.1 引入了行限制子句(使用不​​同的语法);这个答案的更大问题是关系的处理,这在 OP 的问题中明确提到。
    • @mathguy 是的,关系可能是个问题,但在这种情况下,我宁愿使用解析函数。
    • @TimBiegeleisen - 这也是我的观点:即使“限制 1”类型的语法是正确的(在 12.1 及更高版本中是正确的 - 只是不同),它仍然无法解决OP的问题。您对dense_rank() 的回答是正确的。
    • @mathguy 领带有什么问题?它缺少什么?
    【解决方案3】:

    这也可以使用下面的查询来完成,

    场景一:输出两条记录

    WITH employee
    AS (
    SELECT 34 emp_id, 100 rate FROM DUAL
    UNION
    SELECT 22 emp_id, 49 rate FROM DUAL
    UNION
    SELECT 19 emp_id, 49 rate FROM DUAL
    UNION
    SELECT 29 emp_id, 30 rate FROM DUAL
    UNION
    SELECT 17 emp_id, 22 rate FROM DUAL),
    emp_rate_cnt AS 
    (SELECT rownum rown, rate, same_rate_count
       FROM (SELECT rate, count(1) same_rate_count
               FROM employee
              GROUP BY rate
              ORDER BY rate DESC))
    SELECT *
      FROM employee a
     WHERE exists (SELECT 1
                     FROM emp_rate_cnt b
                    WHERE b.rate = a.rate
                      AND b.rown = 2
                      AND b.same_rate_count > 1);
    

    场景2:不输出记录

    WITH employee
    AS (
    SELECT 34 emp_id, 100 rate FROM DUAL
    UNION
    SELECT 22 emp_id, 49 rate FROM DUAL
    UNION
    SELECT 19 emp_id, 50 rate FROM DUAL
    UNION
    SELECT 29 emp_id, 30 rate FROM DUAL
    UNION
    SELECT 17 emp_id, 22 rate FROM DUAL),
    emp_rate_cnt AS 
    (SELECT rownum rown, rate, same_rate_count
       FROM (SELECT rate, count(1) same_rate_count
               FROM employee
              GROUP BY rate
              ORDER BY rate DESC))
    SELECT *
      FROM employee a
     WHERE exists (SELECT 1
                     FROM emp_rate_cnt b
                    WHERE b.rate = a.rate
                      AND b.rown = 2
                      AND b.same_rate_count > 1);
    

    【讨论】:

      【解决方案4】:

      我希望这是最简单的。使用 rownum,因为它是 Oracle。

      SELECT t.employee_id, t.salary
      FROM
      (
          SELECT distinct employee_id, salary, rownum as row from 
          FROM yourTable order by salary desc
      ) t
      WHERE t.row = 2;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多