MySQL练习题:如何取得每个部门薪资前三名的人员名称?

昨日上网偶遇了这个题目,最近正在自学MySQL,思考了一下,给出了一种笨办法:

  • <方法1>

思路:通过分组+排序+limit函数分别求出每个部门的薪资前三名,再通过union合并

mysql> (select e.ename,e.deptno,e.salfrom emp e where deptno="10" order by sal desc limit 3)
   -> union
   -> (select e.ename,e.deptno,e.sal from emp e wheredeptno="20" order by sal desc limit 3)
   -> union
   -> (select e.ename,e.deptno,e.sal from emp e wheredeptno="30" order by sal desc limit 3);

执行结果:

+--------+--------+---------+
| ename | deptno |sal     
+--------+--------+---------+ 
| KING  |    10 | 5000.00 |
| LARK  |    10 | 3200.00 |
| CLARK |    10 | 2450.00 |
| FORD  |    20 | 3000.00 |
| SCOTT |     20 | 3000.00 |
| JONES |     20 | 2975.00 |
| BLAKE |     30 | 2850.00 |
| ALLEN |     30 | 1600.00 |
| TURNER |     30 | 1500.00 |
+--------+--------+---------+

虽然可以成功实现,但代码过于冗长,且处理多部门的情形会很会吃力。在CSDN上看到另一种做法:

  • <方法2>

    mysql>select e.ename, e.deptno,e.sal
    
    from emp e
    
    where
     (select count(*) from emp em where em.sal>e.sal and em.deptno=e.deptno) < 3
    
    order by e.deptno,e.sal desc;
    

执行结果和方法1相同。

毫无疑问,方法2更加简洁高效。那么,怎么理解方法2的逻辑呢?重点在于对count语句条件的理解。

where (select count(*) from emp em where em.sal>e.sal and em.deptno=e.deptno)<3

执行上述语句时,系统会把同一个deptno下每一个的e.sal值与em.sal值进行逐一比对,然后通过count函数来计算符合条件的值的个数。这里的判定条件为<3,所以上述语句实际是包含了三种情形:count(…)is in(0,1,2),下面分别考察。
MySQL练习题:如何取得每个部门薪资前三名的人员名称?_第1张图片
Count(…) = 0:意味着e表取出来的某个值在与em表逐个比对的过程中没有一条线的比对结果是True,即e表中取出的这个值在所有的比对情形中均大于或等于em表,哪一个值会出现这种比对结果呢?最大值。所以,通过count=0的判定情形,我们筛选出了同一deptno下sal的最大值。

Count(…) = 1:意味着e表取出来的某个值在与em表逐个比对的过程中有一条线e的比对结果是True,即em表中有仅1个值是大于e表中取出的这个值的。不难理解,通过这个判定情形我们实际筛选出了第二名。

Count(…) = 2:以此类推,第三名也被筛选出来了。

方法2的语句扩展性很强,比如稍作修改,即可对每个部门薪资排名倒数前三进行筛选:

mysql> select e.ename, e.deptno,e.sal

-> from -> emp e

-> where (select count(*) from emp em where em.sal order by e.deptno,e.sal;

执行结果:

+--------+--------+---------+
| ename  | deptno | sal    |
+--------+--------+---------+
| MILLER |    10 | 1300.00 |
| CLARK  |    10 | 2450.00 |
| LARK  |    10 | 3200.00 |
| SIMITH |    20 |  800.00 |
| ADAMS  |    20 | 1100.00 |
| JONES  |    20 | 2975.00 |
| JAMES  |    30 |  950.00 |
| WARD  |    30 | 1250.00 |
| MARTIN |    30 | 1250.00 |
+--------+--------+---------+

你可能感兴趣的:(Mysql学习)