【问题标题】:How to find third or nᵗʰ maximum salary from salary table?如何从工资表中找到第三个或 nᵗʰ 最高工资?
【发布时间】:2013-04-20 13:00:21
【问题描述】:

如何以优化的方式从工资table(EmpID, EmpName, EmpSalary) 中找到第三或第n 个最高工资?

【问题讨论】:

标签: sql sql-server sql-server-2008


【解决方案1】:

从 SQL Server 的角度回答这个问题,因为这已发布在 SQL Server 部分。

获得第 N 份薪水的方法有很多,我们可以将这些方法分为两个部分,一种是使用 ANSI SQL 方法,另一种是使用 TSQL 方法。您还可以查看这个发现 nth highest salary youtube video,它实际上显示了一些东西。让我们尝试介绍三种编写此 SQL 的方式。

  • 方法 1:- ANSI SQL:- 使用 Simple order by 和 top 关键字。
  • 方法 2:- ANSI SQL:- 使用共同相关的子查询。
  • 方法 3:- TSQL:- 使用 Fetch Next

方法 1:- 使用简单的 order by 和 top。

在这种方法中,我们将结合使用 order by 和 top 关键字。我们可以将我们的思考过程分为 4 个步骤:-

第 1 步:- 降序:- 我们首先使用 order by 子句使其降序。

第二步:- 然后使用TOP关键字,选择TOP N。其中N代表你想要的最高薪级。

第 3 步:- 升序:- 使数据升序。

第 4 步:- 选择前 1 个。这样就完成了。

所以,如果您在 SQL 中记下上述 4 个逻辑步骤,就会出现如下所示的内容。

下面是 SQL 的文本,以防你想执行和测试它。

select top 1 * from (select top 2 EmployeeSalary from tblEmployee order by EmployeeSalary desc) as innerquery order by EmployeeSalary 升序

方法一的参数化问题

方法 1 的最大问题之一是“参数化”。

如果您想将上述 SQL 包装到一个存储过程中,并输入您想要的最高薪水作为参数,则方法 1 会很困难。

您可以使用方法 1 做的一件事是使其成为动态 SQL,但这不是一个优雅的解决方案。让我们看看方法 2,它是一种 ANSI SQL 方法。

方法 2:- 使用共同相关的子查询。

以下是相关子查询解决方案的外观。如果您不熟悉 Co-related 子查询。关联子查询是查询内查询的查询。外部查询首先评估,将记录发送到内部查询,内部查询然后评估并将其发送到外部查询。

查询中的“3”是我们要找出的最高薪水。

从 tblEmployee 中选择 E1.EmployeeSalary 作为 E1 其中 3=(Select count(*) from tblEmployee as E2 where E2.EmployeeSalary>=E1.EmployeeSalary)

所以在上面的查询中我们有一个外部查询:-

从 tblEmployee 中选择 E1.EmployeeSalary 作为 E1

内部查询位于 where 子句中。注意那些指示外部表别名如何在 where 子句中引用的粗体,这使得相互关联的内部和外部查询来回评估:-

where 3=(Select count(*) from tblEmployee as E2 Where E2.EmployeeSalary>=E1.EmployeeSalary)

现在假设您有 3000、4000、1000 和 100 之类的记录,以下是步骤:-

  1. 前 3000 个将被发送到内部查询。
  2. 内部查询现在将检查有多少记录值大于或等于 3000。如果记录数不相等,它将采用下一个值,即 4000。现在对于 3000,只有 2 个值更大大于或等于 3000 和 4000。那么,数字记录计数是否 2>-=3? .NO,所以它需要第二个值,即 4000。
  3. 再次对 4000 有多少记录值大于或等于。如果记录数不相等,则取下一个值,即 1000。
  4. 现在 1000 有 3 条记录大于或等于 1000,(3000,4000 和 1000 自己)。这是 co-related 停止和退出并给出最终输出的地方。

方法 3:- TSQL 提取和下一步。

第三种方法是使用 TSQL。通过使用 Fetch 和 Next,我们可以轻松获得第 N 高。

但请注意,TSQL 代码不适用于其他数据库,我们需要重新重写整个代码。

这将是一个三步过程:-

第 1 步 Distinct and Order by descending: - 首先应用 distinct 和 order by 使薪水下降以及清除重复项。

第 2 步使用偏移量: - 使用 TSQL 偏移量并获取前 N-1 行。其中 N 是我们想要得到的最高薪水。偏移量采用指定的行数,保留其他行。为什么是 (N-1),因为它从零开始。

第 3 步使用 Fetch: - 使用 fetch 并获取第一行。那一行的薪水最高。

SQL 看起来如下所示。

性能比较

下面是性能比较的SQL计划。 以下是 top 和 order by 的计划。

以下是相关查询的计划。您可以看到运营商的数量非常多。所以肯定 co-related 对海量数据表现不佳。

下面是比cor-related更好的TSQL查询计划。

因此,总结起来,我们可以更全面地进行比较,如下表所示。

【讨论】:

    【解决方案2】:
    select * from employee order by salary desc;
    
    +------+------+------+-----------+
    | id   | name | age  | salary    |
    +------+------+------+-----------+
    |    5 | AJ   |   20 | 100000.00 |
    |    4 | Ajay |   25 |  80000.00 |
    |    2 | ASM  |   28 |  50000.00 |
    |    3 | AM   |   22 |  50000.00 |
    |    1 | AJ   |   24 |  30000.00 |
    |    6 | Riu  |   20 |  20000.00 |
    +------+------+------+-----------+
    
    
    
    
    select distinct salary from employee e1 where (n) = (select count( distinct(salary) ) from employee e2 where e1.salary<=e2.salary);
    

    将 n 替换为第 n 个最高薪水的数字。

    【讨论】:

      【解决方案3】:

      在 SQL Server 2012+ 中,OFFSET...FETCH 将是实现此目的的有效方法:

      DECLARE @N AS INT;
      SET @N = 3;
      
      SELECT
          EmpSalary
      FROM
          dbo.Salary
      ORDER BY
          EmpSalary DESC
      OFFSET (@N-1) ROWS
      FETCH NEXT 1 ROWS ONLY
      

      【讨论】:

        【解决方案4】:
        SELECT TOP 1 salary 
        FROM   employee 
        WHERE  salary IN (SELECT DISTINCT TOP 3 salary 
                          FROM   employee 
                          ORDER  BY salary DESC) 
        ORDER  BY salary ASC 
        

        【讨论】:

          【解决方案5】:

          使用 CTE 和 FIRST_VALUE 函数查找第 N 个最大值。 -- 5th 最高薪水

          ;WITH CTE_NTH_SAL AS 
              (SELECT FIRST_VALUE(ESAL) OVER(ORDER BY ESAL DESC) AS ESAL,
                  1 AS ID
              FROM EMPLOYEE
              UNION ALL
              SELECT FIRST_VALUE(EMP.ESAL) OVER(ORDER BY EMP.ESAL DESC) AS ESAL,
                  ID
              FROM EMPLOYEE EMP,
                  (SELECT ESAL,
                  ID+1 AS ID
                  FROM CTE_NTH_SAL) CTE_NTH_SAL
                  WHERE EMP.ESAL<CTE_NTH_SAL.ESAL
                          AND CTE_NTH_SAL.ID<=5 )
              SELECT DISTINCT ESAL
          FROM CTE_NTH_SAL
          WHERE ID=5
          

          对于样本结果集和更多方式clickhere

          【讨论】:

            【解决方案6】:

            从表中找出第 N 个最高薪水。这是使用 dense_rank() 函数完成此任务的一种方法。

            select linkorder from u_links
            
            select max(linkorder) from u_links
            
            select max(linkorder) from u_links where linkorder < (select max(linkorder) from u_links)
            
            select top 1 linkorder 
                   from ( select distinct top 2 linkorder from u_links order by linkorder desc) tmp 
            order by linkorder asc
            

            DENSE_RANK: 1. DENSE_RANK 计算行在有序行组中的排名,并将排名作为数字返回。秩是从 1 开始的连续整数。 2. 此函数接受任何数字数据类型的参数并返回 NUMBER。 3. 作为一个分析函数,DENSE_RANK 根据 order_by_clause 中 value_exprs 的值计算查询返回的每一行相对于其他行的排名。 4. 在上面的查询中,排名是根据雇员表的sal 返回的。在平局的情况下,它为所有行分配相同的排名。

            WITH result AS ( 
                 SELECT linkorder ,DENSE_RANK() OVER ( ORDER BY linkorder DESC ) AS  DanseRank 
            FROM u_links ) 
            SELECT TOP 1 linkorder FROM result WHERE DanseRank = 5
            

            【讨论】:

              【解决方案7】:

              如果你想优化方式意味着使用TOP关键字,所以第n个最大和最小薪水查询如下,但查询看起来很棘手,因为使用聚合函数名称以相反的顺序:

              N个最高工资:

              SELECT MIN(EmpSalary)
              FROM Salary
              WHERE EmpSalary IN(SELECT TOP N EmpSalary FROM Salary ORDER BY EmpSalary DESC) 
              

              例如:3 最高工资:

              SELECT MIN(EmpSalary)
              FROM Salary
              WHERE EmpSalary IN(SELECT TOP 3 EmpSalary FROM Salary ORDER BY EmpSalary DESC) 
              

              N 最低工资:

              SELECT MAX(EmpSalary)
              FROM Salary
              WHERE EmpSalary IN(SELECT TOP N EmpSalary FROM Salary ORDER BY EmpSalary ASC)
              

              例如:3 最低工资:

              SELECT MAX(EmpSalary)
              FROM Salary
              WHERE EmpSalary IN(SELECT TOP 3 EmpSalary FROM Salary ORDER BY EmpSalary ASC)
              

              【讨论】:

              • 最简单,最容易记住。 +1
              • 要获得最高薪水,为什么我们按 ASC 顺序做,它必须按 DESC 顺序完成,如果我们有这样的薪水 7000,10000,11000,500,800,900,12000,那么内部查询排序将导致 top3 表示 500,800,900,其中最大值为 900,但 900 不是 3 最大值,3 最高薪水为 10000。
              • 例如:3 最高工资:必须是这样 SELECT Min(EmpSalary) FROM Salary WHERE EmpSalary IN(SELECT TOP 3 EmpSalary FROM Salary ORDER BY EmpSalary DESC)
              • 漂亮的解决方案
              【解决方案8】:

              试试这个代码:-

              SELECT *
                 FROM one one1
                 WHERE ( n ) = ( SELECT COUNT( one2.salary )
                                 FROM one one2
                                 WHERE one2.salary >= one1.salary
                               )
              

              【讨论】:

                【解决方案9】:

                从表中获取第三高的值

                SELECT * FROM tableName ORDER BY columnName DESC LIMIT 2, 1
                

                【讨论】:

                • SELECT Distinct columnName FROM tableName ORDER BY columnName DESC LIMIT 2, 1
                【解决方案10】:

                子查询总是需要更多时间:

                使用下面的查询来获取任何最高和最低的数据:

                最高数据:select *from business order by id desc limit 3,1;

                最低数据:select *from business order by id asc limit 3,1;

                可以用N代替3得到第n个数据。

                【讨论】:

                  【解决方案11】:

                  注意:请将查询中的 OFFSET 3 替换为任意第 N 个整数

                  SELECT EmpName,EmpSalary
                  FROM SALARY
                  ORDER BY EmpSalary DESC
                  OFFSET 3 ROWS 
                  FETCH NEXT 1 ROWS ONLY
                  

                  说明

                  仅获取下 1 行

                  只返回 1 行

                  偏移 3 行

                  排除前3条记录在这里你可以任意整数

                  【讨论】:

                    【解决方案12】:
                    SELECT EmpSalary 
                    FROM salary_table 
                    GROUP BY EmpSalary 
                    ORDER BY EmpSalary DESC LIMIT n-1, 1;
                    

                    【讨论】:

                      【解决方案13】:

                      MySQL 测试解决方案,假设 N = 4:

                      select min(CustomerID) from (SELECT distinct CustomerID FROM Customers order by CustomerID desc LIMIT 4) as A;
                      

                      另一个例子:

                      select min(country) from (SELECT distinct country FROM Customers order by country desc limit 3);
                      

                      【讨论】:

                        【解决方案14】:

                        SELECT * FROM (select distinct Salary from Customers order by Salary DESC) limit 4,1;

                        限制 4,1 表示保留前 4 行,然后选择下一行。

                        限制和行号取决于您使用的平台。

                        试试这个,它会工作的。

                        【讨论】:

                          【解决方案15】:
                          select 
                              Min(salary) 
                          from ( select salary from employees order by salary desc) t
                          where rownum<=3;
                          

                          对于第二高的薪水,将上述查询中的 3 更改为 2,将第 N 高的薪水更改为 N,其中 N = 1,2,3,4....

                          【讨论】:

                            【解决方案16】:

                            试试这个...

                            SELECT MAX(salary) FROM employee WHERE salary NOT IN (SELECT * FROM employee ORDERBY salary DESC LIMIT n-1)
                            

                            【讨论】:

                              【解决方案17】:

                              显示所有第三高的薪水:

                              select * from emp where sal=
                              (SELECT DISTINCT sal FROM emp ORDER BY sal DESC LIMIT 3,1) ;
                              

                              仅显示第三高的薪水:

                              SELECT DISTINCT sal FROM emp ORDER BY sal DESC LIMIT 3,1
                              

                              【讨论】:

                                【解决方案18】:

                                使用ROW_NUMBER(如果你想要一个)或DENSE_RANK(对于所有相关行):

                                WITH CTE AS
                                (
                                    SELECT EmpID, EmpName, EmpSalary,
                                           RN = ROW_NUMBER() OVER (ORDER BY EmpSalary DESC)
                                    FROM dbo.Salary
                                )
                                SELECT EmpID, EmpName, EmpSalary
                                FROM CTE
                                WHERE RN = @NthRow
                                

                                【讨论】:

                                • 如何从表中获取最低工资记录?从 cmn_pat_x_insurance ins 中选择 ins.KYS_ID 、 ins.FKYS_INS_ID 其中 ins.FKYS_PAT_ID='1253_717' 和 ins.FKYS_INS_TYPE in(1) 和 ins.BOL_TYPE in(1,3) 和 ins.salary in (min(ins.salary))
                                • 想象一下,employee 表中有 10,0000 条记录。如果我使用上面的查询,性能会降低6-10倍。
                                • @BimalDas:那么您在EmpSalary 列上没有索引。还有,相比什么减少了? ROW_NUMBER 方法的优点是您可以使用..OVER(PARTITION BY GroupColumn OrderBy OrderColumn)。因此,您可以使用它来获取组,但仍然可以访问它的任何列。
                                • @BimalDas:不,它不是创建临时表。 cte 通常不会在任何地方实现。它更像是一个内联视图或命名子查询。
                                • @KennyLJ:嗯,这是一个 SQL-Server 问题,LIMIT 是 MySql。在 MS-SQL-Server 中,您需要子查询或 CTE,因为您不能在 WHERE 中使用 ROW_NUMBERWhy you can’t use ROW_NUMBER() In the WHERE Clause
                                【解决方案19】:

                                优化方式:使用limit代替子查询。

                                select distinct salary from employee order by salary desc limit nth, 1;
                                

                                在此处查看限制语法http://www.mysqltutorial.org/mysql-limit.aspx

                                【讨论】:

                                • 是的!这是非常简单和干净的解决方案。
                                【解决方案20】:

                                --第n高薪

                                select * 
                                from (select lstName, salary, row_number() over( order by salary desc) as rn 
                                      from employee) tmp
                                where rn = 2
                                

                                --(nth -1) 最高薪水

                                select * 
                                from employee e1
                                where 1 = (select count(distinct salary)  
                                           from employee e2
                                           where e2.Salary > e1.Salary )
                                

                                【讨论】:

                                  【解决方案21】:
                                  select min(salary) 
                                  from (select salary 
                                        from employee 
                                        where rownum < n+1 
                                        order by salary desc);
                                  

                                  【讨论】:

                                    【解决方案22】:

                                    不使用子查询的工资表中的第三个或第 n 个最高工资

                                    select salary from salary
                                       ORDER   BY salary DESC
                                       OFFSET  N-1 ROWS
                                       FETCH NEXT 1 ROWS ONLY
                                    

                                    对于第三高的薪水,用 2 代替 N-1

                                    【讨论】:

                                    • 重要的是,OFFSET FETCH 可从 SQL Server 2012 + 版本获得。
                                    【解决方案23】:
                                    SELECT MIN(COLUMN_NAME)
                                    FROM   (
                                               SELECT DISTINCT TOP 3     COLUMN_NAME
                                               FROM   TABLE_NAME
                                               ORDER BY
                                                      COLUMN_NAME        DESC
                                           ) AS 'COLUMN_NAME'
                                    

                                    【讨论】:

                                      【解决方案24】:

                                      通过子查询:

                                      SELECT salary from
                                      (SELECT rownum ID, EmpSalary salary from
                                      (SELECT DISTINCT EmpSalary from salary_table order by EmpSalary DESC)
                                      where ID = nth)
                                      

                                      【讨论】:

                                        【解决方案25】:
                                        set @n = $n
                                        
                                        SELECT a.* FROM ( select a.* , @rn = @rn+1  from EMPLOYEE order by a.EmpSalary desc ) As a  where rn = @n
                                        

                                        【讨论】:

                                          【解决方案26】:

                                          方法一:

                                          SELECT TOP 1 salary FROM (
                                          SELECT TOP 3 salary 
                                           FROM employees 
                                            ORDER BY salary DESC) AS emp 
                                           ORDER BY salary ASC
                                          

                                          方法二:

                                            Select EmpName,salary from
                                            (
                                              select EmpName,salary ,Row_Number() over(order by salary desc) as rowid      
                                               from EmpTbl)
                                             as a where rowid=3
                                          

                                          【讨论】:

                                          • 方法1可以排序: SELECT TOP 1 SALARY FROM (SELECT TOP 3 SALARY FROM EMPLOYEES) *原因- 因为默认是升序的
                                          【解决方案27】:

                                          请参阅以下查询以获得第 n 高薪水。通过这种方式,您将获得 MYSQL 中第 n 高的薪水。如果您只想获得第 n 个最低工资,则需要在查询中将 DESC 替换为 ASC。

                                          【讨论】:

                                          • 问题是关于 SQL-Server 而不是 MySQL。
                                          【解决方案28】:
                                          Select TOP 1 Salary as '3rd Highest Salary' from (SELECT DISTINCT TOP 3 Salary from Employee ORDER BY Salary DESC) a ORDER BY Salary ASC;
                                          

                                          我的薪水排名第三

                                          【讨论】:

                                            【解决方案29】:

                                            如果使用子查询太简单了!

                                            SELECT MIN(EmpSalary) from (
                                            SELECT EmpSalary from Employee ORDER BY EmpSalary DESC LIMIT 3
                                            );
                                            

                                            您可以在这里只更改 LIMIT 约束之后的第 n 个值。

                                            这里的子查询 Select EmpSalary from Employee Order by EmpSalary DESC Limit 3;将返回员工的前 3 名工资。从结果中,我们将使用 MIN 命令选择最低工资,以获得员工的第三个 TOP 工资。

                                            【讨论】:

                                            • 收到此错误。错误代码:1248 每个派生表都必须有自己的别名
                                            • 为其添加别名.. SELECT MIN(EmpSalary) from (SELECT EmpSalary from Employee ORDER BY EmpSalary DESC LIMIT 3) as s;
                                            • 只需使用 DISTINCT 以避免重复 SELECT MIN(EmpSalary) from ( SELECT DISTINCT(EmpSalary) from Employee ORDER BY EmpSalary DESC LIMIT 3 );
                                            【解决方案30】:
                                            SELECT TOP 1 salary FROM (
                                               SELECT TOP 3 salary 
                                               FROM employees 
                                               Group By salary ORDER BY salary DESC ) AS emp 
                                            ORDER BY salary ASC
                                            

                                            【讨论】:

                                              猜你喜欢
                                              • 2012-07-31
                                              • 1970-01-01
                                              • 2016-06-27
                                              • 2019-06-23
                                              • 1970-01-01
                                              • 2021-04-20
                                              • 2015-10-21
                                              • 2018-06-11
                                              相关资源
                                              最近更新 更多