牛客网数据库SQL实战12—— 获取所有部门中当前员工薪水最高的相关信息

牛客网数据库SQL实战12—— 获取所有部门中当前员工薪水最高的相关信息

题目描述

获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));

输入描述:

输出描述:

dept_no emp_no salary
d001 10001 88958
d002 10006 43311
d003 10005 94692
d004 10004 74057
d005 10007 88070
d006 10009 95409

我的解答

select d.dept_no,d.emp_no,max(s.salary) as salary
from dept_emp d
left join salaries s
on d.emp_no = s.emp_no
where d.to_date='9999-01-01'
and s.to_date='9999-01-01'
group by d.dept_no

此题思路如下:

  1. 先用LEFT JOIN连接两张表,限制条件是两张表的emp_no相同,即d.emp_no = s.emp_no;
  2. 选取每个员工当前的工资水平,用d.to_date = ‘9999-01-01’ AND s.to_date = '9999-01-01’作条件限制,因为此表中每条最新记录的 to_date 都用 9999-01-01 表示;
  3. 用GROUP BY d.dept_no将每个部门分为一组,用MAX()函数选取每组中工资最高者;
  4. 将salaries用s代替,dept_emp用d代替,最后将MAX(s.salary)用salary代替后输出。

我这种做法可以通过检测,但是看了其他网友的解析后,,我发现这种做法有问题,因为GROUP BY 默认取非聚合的第一条记录

漏洞:

  1. emp_no直接和group by dept_no一起使用,拿到了最大salary但是存在emp_no取值其实与salary不匹配的问题;
  2. 先使用group by获得最高salary,再去用最高salary匹配两表返回dept_no,emp_no信息,这存在A部门的最高薪水,等于B部门非最高薪水时,B部门的非最高薪水也会被显示出来。在此我将我的答案提供出来,自认为不存在以上两点漏洞:

解法一:(如果同部门有多条同等最大salary,一起显示出来)

select r.dept_no,ss.emp_no,r.maxSalary from (
select d.dept_no,max(s.salary)as maxSalary from dept_emp d,salaries s
where d.emp_no=s.emp_no
and d.to_date='9999-01-01' 
and s.to_date='9999-01-01'
group by d.dept_no
)as r,salaries ss,dept_emp dd
where r.maxSalary=ss.salary
and r.dept_no=dd.dept_no
and dd.emp_no=ss.emp_no
and ss.to_date='9999-01-01'
and dd.to_date='9999-01-01'
order by r.dept_no asc

解法二:(如果同部门有多条同等最大salary,仅显示一条)

select r.dept_no,r.emp_no,max(r.salary) from (
select d.dept_no,d.emp_no,s.salary from dept_emp d,salaries s
where d.emp_no=s.emp_no
and d.to_date='9999-01-01' 
and s.to_date='9999-01-01'
order by s.salary desc
)as r
group by r.dept_no
order by r.dept_no asc

注明两点:

  1. 题目忘记写一条信息,按照部门编号排序
  2. 解法二利用了GROUP BY 默认取非聚合数据的第一条记录,所以先排好序,拿到的emp_no第一条信息,也是与最大salary匹配的
  3. 解法一中使用多表取值,where筛选条件和内连接,on筛选条件,效果一致,可以替换。效率根据不同表的结构,数据结构而定。

我觉得最好的答案

1、方法一:使用窗口排序函数
DENSE_RANK() OVER(PARTITION dept_no ORDER BY salary DESC)可以得出以
部门为单位的员工的工资排名,可以满足并列第1的要求

SELECT D.dept_no,D.emp_no,D.salary
FROM(
    SELECT
           DENSE_RANK() OVER (PARTITION BY C.dept_no ORDER BY C.salary DESC) AS raking,
           C.dept_no,
           C.emp_no,
           C.salary
    FROM (
          SELECT
                A.dept_no,
                A.emp_no,
                B.salary
          FROM 
                dept_emp A
                INNER JOIN salaries B ON A.emp_no = B.emp_no
          WHERE 
                A.to_date = '9999-01-01'
                AND B.to_date = '9999-01-01'
         ) C
     ) D 
WHERE D.raking = 1
ORDER BY D.dept_no

2、方法二:如果mysql数据库没有排序函数,则可以使用非等值自连接的方法来实现类似DENSE_RANK()
函数的功能,语句比较长,可以不过原理简单的,如下:

SELECT D.dept_no,D.emp_no,D.salary FROM(
    SELECT (
        SELECT COUNT( DISTINCT F.salary ) 
            FROM(
                  SELECT
                    A.dept_no,
                    A.emp_no,
                    B.salary 
                  FROM
                    dept_emp A
                    INNER JOIN salaries B ON A.emp_no = B.emp_no 
                  WHERE
                    A.to_date = '9999-01-01' 
                    AND B.to_date = '9999-01-01' 
                ) AS F 
        WHERE
            F.salary >= C.salary 
            AND F.dept_no = C.dept_no 
        ) AS raking,
           C.dept_no,C.emp_no,C.salary FROM (
            SELECT
                A.dept_no,
                A.emp_no,
                B.salary
            FROM 
                dept_emp A
            INNER JOIN salaries B ON A.emp_no = B.emp_no
            WHERE 
            A.to_date = '9999-01-01'
            AND B.to_date = '9999-01-01' ) C ) D 
WHERE D.raking = 1
ORDER BY D.dept_no

你可能感兴趣的:(牛课网练习)