Leetcode184.部门工资最高的员工(中等)

这道题写的头疼,还是因为太菜了吧。。。

题目
Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。

+----+-------+--------+--------------+
| Id | Name  | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1  | Joe   | 70000  | 1            |
| 2  | Henry | 80000  | 2            |
| 3  | Sam   | 60000  | 2            |
| 4  | Max   | 90000  | 1            |
+----+-------+--------+--------------+

Department 表包含公司所有部门的信息。

+----+----------+
| Id | Name     |
+----+----------+
| 1  | IT       |
| 2  | Sales    |
+----+----------+

编写一个 SQL 查询,找出每个部门工资最高的员工。例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。

+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT         | Max      | 90000  |
| Sales      | Henry    | 80000  |
+------------+----------+--------+

审题
如果只要每个部门的最高工资这就是一个特别特别简单的题目 分组+连接即可
但这里还要涉及到最高工资对应的姓名,如果分组取Name其实取到的是每个分组的第一个姓名 不一定是最高工资对应的姓名。 这里可以对各个部门的最高工资和Employee表进行连接得到

产生数据

CREATE TABLE employee2 (
  Id INT,
  NAME CHAR(10),
  Salary INT,
  DepartmentId CHAR(2)
) ;

CREATE TABLE Department (Id INT, NAME CHAR(10)) ;

INSERT INTO employee2 
VALUE(1, 'Joe', 70000, '1'),
(2, 'Hery', 80000, '2'),
(3, 'Sam', 60000, '2'),
(4, 'Max', 90000, '1');

INSERT INTO Department VALUE(1, 'IT'),(2, 'Sales');

自己的解答
开始绝望
①、选出每个DepartmentId的最高工资

SELECT DepartmentId, MAX(Salary)
FROM Employee2
GROUP BY DepartmentId;

②、①得到的结果与Department表连接得到部门名

SELECT tmp.salary, dep.`Name`
FROM (SELECT DepartmentId, MAX(Salary) AS salary
FROM Employee2
GROUP BY DepartmentId) AS tmp
JOIN Department AS dep
ON tmp.DepartmentId = dep.`Id`;

③、②的结果和Employee表连接 得到最高工资对应的姓名

SELECT tmp2.name AS Department, e.`NAME` AS  Employee, tmp2.salary AS salary
FROM employee2 AS e
JOIN (SELECT tmp.salary, dep.`Name`
FROM (SELECT DepartmentId, MAX(Salary) AS salary
FROM Employee2
GROUP BY DepartmentId) AS tmp
LEFT JOIN Department AS dep
ON tmp.DepartmentId = dep.`Id`) tmp2
ON e.`Salary` = tmp2.salary;

执行代码



挺好的呀, 然而。。。



这里有一个坑,是Department如果为空 应该返回空表。

这个可以判断空表

LENGTH(TRIM(Id))>0
FROM Department 

但是不知道怎么加进去。。。

为了解决这个问题尝试先用连接再分组
想法:如果用左连接 department表为主表当他为空的时候也就可以解决了
然而。。。

SELECT tmp.Department, e2.`NAME` AS  Employee, tmp.salary
FROM (SELECT MAX(e.`Salary`) AS Salary, dep.`Name` AS Department
FROM Department dep
LEFT JOIN employee2  e
ON e.`DepartmentId` = dep.`Id`
GROUP BY dep.`Name`) tmp
LEFT JOIN employee2 e2
ON tmp.Salary = e2.`Salary`

结果:



如果Employee表为空,就又gg了。。。

绝望

挣扎了一会儿。。放弃了
正确的解答
1.in的无情操作
①、选出每个DepartmentId的最高工资

SELECT DepartmentId, MAX(Salary)
FROM Employee2
GROUP BY DepartmentId;

注意:有可能有多个员工同时拥有最高工资,所以最好在这个查询中不包含雇员名字的信息。

而且分组取name,其实取得是每个分组的第一个name

②、in的无情操作
将两表连接

SELECT *
FROM employee2 e
JOIN department dep
ON e.`DepartmentId` = dep.`Id`


之前接触过的in操作都是单个的,两个的也是可以的

③将(dep.Id, e.Salary)在表一种的结果取出

SELECT *
FROM employee2 e
JOIN department dep
ON e.`DepartmentId` = dep.`Id`
WHERE (dep.`Id`, e.`Salary`) IN (SELECT DepartmentId, MAX(Salary)
FROM Employee2
GROUP BY DepartmentId);

再把对应的列名取出取别名即可

SELECT dep.`Name` AS Department, e.`NAME` AS Employee, e.`Salary`
FROM employee e
JOIN department dep
ON e.`DepartmentId` = dep.`Id`
WHERE (e.`DepartmentId`, e.`Salary`) IN (SELECT DepartmentId, MAX(Salary)
FROM Employee
GROUP BY DepartmentId);

终于通过了。。。
思考:这里如果出现表为空的情况可以用第二部中的内连接来避免, 如果一个表为空,则内连接的结果为空。

但如果用左连接呢

使用left join 要注意 部门名字 不能是NULL 。所以,如果使用Left join在官方解答后面加上一句判断 AND Department.name is not null...

SELECT
    Department.name AS 'Department',
    Employee.name AS 'Employee',
    Salary
FROM
    Employee
LEFT JOIN
    Department ON Employee.DepartmentId = Department.Id 
WHERE
    (Employee.DepartmentId , Salary) IN
    (   SELECT
            DepartmentId, MAX(Salary)
        FROM
            Employee
        GROUP BY DepartmentId
    )
AND Department.name is not null
;

后期补充
其实我自己的解答虽然结果是对的 但存在很大问题
有可能有多个员工同时拥有最高工资 如果IT部门也有一个工资为8000的员工 只靠salary连接就会出现很大的问题,其实这里还应该将②中的部门id保留 靠salary和部门id一起连接 下面试一试

SELECT tmp2.name AS Department, e.`NAME` AS  Employee, tmp2.salary AS salary
FROM employee AS e
JOIN (SELECT dep.`Id`, tmp.salary, dep.`Name`
FROM (SELECT DepartmentId, MAX(Salary) AS salary
FROM Employee
GROUP BY DepartmentId) AS tmp
JOIN Department AS dep
ON tmp.DepartmentId = dep.`Id`) tmp2
ON e.`Salary` = tmp2.salary AND e.`DepartmentId` = tmp2.Id;

通过咯。。。

总结
前面写的有些乱,在这里总结一下吧
方法一、
先找出每个部门的最高薪水。
连接员工表和部门表,group by对部门分组,再求每组的最高薪水。用子查询得出临时表tmp(id,name,m)。

SELECT dep.id, dep.name,MAX(E.salary) AS m
FROM Department AS dep
JOIN Employee2 AS E
ON (dep.id = E.departmentid)
GROUP BY dep.id,dep.name

再次,连接员工表和临时表tmp,条件是部门id相同且薪水与每个部门最高薪水相同。与上面的组合起来得出算法:

select tmp.name as `Department`,E2.name as `Employee`,E2.Salary
from Employee as E2
join (
SELECT dep.id, dep.name,MAX(E.salary) AS m
FROM Department AS dep
JOIN Employee2 AS E
ON (dep.id = E.departmentid)
GROUP BY dep.id,dep.name
) as tmp
on (E2.departmentid = tmp.id and tmp.m = E2.salary);

可行

另外员工表中有部门id和薪水,但没有部门name。可先求部门的最高薪水,形成临时表,再连接员工表(需要部门Id和Salary两个条件)和部门表【两者的顺序可以调换】,取出部门name和员工name。

select D.name as `Department`,E.name as `Employee`,E.Salary
from Employee as E
join (
    select E1.departmentid,max(E1.salary) as m
    from Employee as E1
    group by E1.departmentid
) as F
    on (E.departmentid = F.departmentid and F.m = E.salary)
join Department as D
    on (F.departmentid = D.id)

方法二、
对每一个员工,找出员工所在部门的最高薪水。此处的查找过程,用子查询实现。如果员工的薪水等于部门的最高薪水就是结果。

select D.name as `Department`,E.name as `Employee`,E.Salary
from Employee as E
join Department as D
    on (E.departmentid = D.id)
where E.salary = (
    select max(E1.salary) 
    from Employee as E1
    where E1.departmentid = E.departmentid
)

方法三、
当然二元组(部门id,部门最高薪水)作为整体t,结合in判断t是否在已存在的组合中。

select D.name as `Department`,E.name as `Employee`,E.Salary
from Employee as E
join Department as D
    on (E.departmentid = D.id)
where (E.departmentid,E.salary) in (
    select E1.departmentid,max(E1.salary) 
    from Employee as E1
    where E1.departmentid
    group by E1.departmentid
)

你可能感兴趣的:(Leetcode184.部门工资最高的员工(中等))