【问题标题】:MYSQL query to find the all employees with nth highest salaryMYSQL查询工资第n高的所有员工
【发布时间】:2014-07-31 11:49:09
【问题描述】:

两张表分别是salary_employee和employee

员工工资

salary_id  emp_id  salary

员工

emp_id |    first_name | last_name |    gender  | email | mobile  | dept_id  | is_active

查询n =1,2,3,...任意整数的nth最高工资的所有员工

SELECT  a.salary, b.first_name 
FROM    employee_salary a 
JOIN    employee b 
ON      a.emp_id = b.emp_id 
WHERE   a.salary = (
                      SELECT    salary 
                      FROM      employee_salary  
                      GROUP BY  salary 
                      DESC     
                      LIMIT 1 OFFSET N-1
                   )

我的问题:

1) 有没有更好和优化的方法可以查询这个,


2) 使用 LIMIT 是一个不错的选择


3) 我们有更多的选项来计算第 n 高的薪水,哪个是最好的,应该遵循什么,什么时候遵循?

一个选项使用:

SELECT *
   FROM employee_salary t1
   WHERE ( N ) = ( SELECT COUNT( t2.salary )
                   FROM employee_salary t2 
                   WHERE  t2.salary >=  t1.salary 
                 )

使用排名法

SELECT salary
FROM
(
  SELECT @rn := @rn + 1 rn,
       a.salary
  FROM tableName a, (SELECT @rn := 0) b
  GROUP BY salary DESC
) sub
WHERE sub.rn = N

【问题讨论】:

  • 您已经很好地总结了执行此操作的不同方法。你的实际问题是什么?如果性能是一个问题,您应该在您的系统上使用您的数据尝试不同的方法,然后选择最有效的方法。
  • 问题是如何优化查询,问题是什么时候用什么?为什么一个比另一个更好以及它的局限性。

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


【解决方案1】:

你问了什么看起来是一个合理的问题。 SQL 中有不同的做事方式,有时某些方法比其他方法更好。排名问题只是众多例子之一。您的问题的“答案”是,一般而言,order by 在 MySQL 中的性能将优于group by。尽管这取决于特定数据以及您认为“更好”的数据。

这个问题的具体问题是你有三个不同的查询,它们返回三个不同的东西。

第一个返回具有相同“密集等级”的所有员工。该术语是故意使用的,因为它对应于 MySQL 不支持的 ANSI dense_rank() 函数。因此,如果您的薪水是 100、100 和 10,它将返回两行排名为 1 的行和排名为 2 的行。

如果有平局,第二个返回不同的结果。如果工资是 100、100、10,则此版本将不返回排名为 1 的行,排名为 2 的行为两行,排名为 3 的行为一行。

第三个返回一个完全不同的结果集,只是薪水和薪水的排名。

我的评论旨在尝试对您的数据进行查询。事实上,您应该从功能和性能的角度来决定您真正想要什么。

【讨论】:

    【解决方案2】:

    LIMIT 要求 SQL 浏览 0 到 N 之间的所有记录,因此需要在您想要查看的排名靠后的位置增加时间。但是,IMO 无法更好地解决这个问题。

    • 正如 Gordon Linoff 建议的那样:针对您的数据集运行您的选项,使用常用的排名(哪些排名经常被查询,哪些不是?结果可能在排名 1 上很快,但在排名 100 上很糟糕)。

    • 执行并分析Query Execution Plan 并相应地创建索引(例如在薪水列上)并重新测试您的查询。

    其他选项:

    选项 4:

    你可以建立一个排名表作为缓存。您的 Limit-Query 的执行计划显示 (see sqlfiddle here),mysql 已经创建了一个临时表来解决查询。

    优点:简单快捷 缺点:每次数据更改时都会强制您重新生成排名表

    选项 5:

    您可以重新考虑如何定义“等级”。 如果我们有以下薪水:

    1. 100'000
    2. 100'000
    3. 80'000

    员工 Nr 3 被认为是 3 级还是 2 级? 1 和 2 是否在同一等级(等级 1),但 3 在等级 3 上?

    如果定义rank = order,可以大大简化查询到

    选择 a.salary, b.first_name FROM employee_salary a, 员工 b 哪里 a.emp_id = b.emp_id 按工资顺序排列 限制 1 偏移量 4

    演示:http://sqlfiddle.com/#!2/e7321d/1/0

    【讨论】:

    • 如何在不跳过的情况下给出排名可以通过 SELECT t1.emp_id, t1.salary, (SELECT COUNT(*) FROM employee_salary t2 WHERE t2.salary > t1.salary) + 1 来完成AS rnk FROM employee_salary t1 order by rnk
    【解决方案3】:

    试试这个,

    SELECT * FROM one as A WHERE ( n ) = ( SELECT COUNT(DISTINCT(b.salary)) FROM one as B  WHERE 
    B.salary >= A.salary )
    

    【讨论】:

    • 小心添加一些细节,为什么你认为这样更好?
    【解决方案4】:

    假设emp_salary表有以下记录:

    并且您想选择所有具有第 n 个(N=1,2,3 等)最高/最低(仅根据您的需要更改 >(最高)、

    SELECT DISTINCT(a.salary), 
           a.id, 
           a.name 
           FROM emp_salary a 
           WHERE N = (SELECT COUNT( DISTINCT(b.salary)) FROM emp_salary b
                      WHERE b.salary >= a.salary 
                     );
    

    例如,如果要选择所有薪水第二高的员工,请使用以下 sql:

     SELECT DISTINCT(a.salary), 
           a.id, 
           a.name 
           FROM emp_salary a 
           WHERE 2 = (SELECT COUNT( DISTINCT(b.salary)) FROM emp_salary b
                      WHERE b.salary >= a.salary 
                     );
    

    但是如果你只想显示第二高的薪水(只有单条记录),使用下面的sql:

    SELECT DISTINCT(a.salary), 
           a.id, 
           a.name 
           FROM emp_salary a 
           WHERE 2 = (SELECT COUNT( DISTINCT(b.salary)) FROM emp_salary b
                      WHERE b.salary >= a.salary 
                     ) limit 1;
    

    【讨论】:

      猜你喜欢
      • 2012-07-31
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多