--2023.11.3更新(窗口函数版)

select
    a.dept_no as dept_no,
    a.emp_no as emp_no,
    a.salary as maxSalary
from
    (select
    de.dept_no as dept_no, 
    sl.emp_no as emp_no, 
    sl.salary as salary, 
    rank() over(partition by de.dept_no order by sl.salary desc)
    as rk
    from dept_emp de join salaries sl on de.emp_no = sl.emp_no)as a
where rk = 1

--2022.4.1.更新

先说一下,很多高分答案放在mysql里都是错的

这个和牛客网这个运行sql的编辑器也有关系,错的他也就给你运行出来了,离了个大谱。 像这个排名第一的答案,也是错的,我在自己本地mysql一跑就报错,因为它的语法就有问题:

select dept_no,d.emp_no,max(s.salary) from dept_emp d
join salaries s on d.emp_no = s.emp_no
group by d.dept_no;

group by分组之后再不能有select dept_no,d.emp_no这样会造成歧义的查询语句,只能使用聚合函数,或者查询分组的字段,类似这样:

select max(s.salary),d.dept_no from dept_emp d
join salaries s on d.emp_no = s.emp_no
group by d.dept_no;

至于原因,我这篇文章后面会转载一篇别人的博客,此博客专门说了这个问题。 其他错误的还有什么having之后用了聚合语句,一下就出来的,这种在mysql中都跑不出来,虽然牛客的编辑器中可以,但不代表它们就是对的。

下面说一下正确的思路:

先通过分组和聚合函数找出按部门分组后,每组内最高的工资都是多少,然后将这个当做一张表,再用这个表和其他两个表进行关联查询,下面这个是我用CTE风格写的代码,在mysql 8.0及之后的版本中可以运行,因为之前的版本不支持这种风格:

WITH q1 AS (SELECT de.dept_no,max(sal.salary) salary
FROM dept_emp de JOIN salaries sal
ON de.emp_no = sal.emp_no GROUP BY de.dept_no
) ,
q2 AS (
SELECT de.dept_no,de.emp_no,q1.salary
FROM dept_emp de JOIN salaries sal ON de.emp_no = sal.emp_no
JOIN q1 ON q1.dept_no = de.dept_no AND q1.salary = sal.salary
)
select * from q2;

为什么这样写,因为和一年前写的相比,我觉得自己对sql的理解又多了一些,另外不排除一些我有点想炫技的想法。 如果CTE风格暂时接受不了,就看下面我一年前写的吧。

切记:上述查询语句有一个细节需要注意,就是在q1与其他两张表关联时,我个人认为应该先进行员工表和薪资表的关联,再关联q1,同时要满足:q1.dept_no = de.dept_no AND q1.salary = sal.salary,如果只满足q1.salary = sal.salary条件,有可能某个组内的最高工资和其他组内的不是最高的工资相同从而把这条不是最高工资的员工信息查出来,这也是与题目要求不符合的,所以我觉得需要注意一下这的书写顺序和需要同时满足的条件。

mysql语句有自己严格的语法,一定要按照逻辑写出符合语法的sql,不能想当然。

最好写完再去自己的mysql上跑一下,验证一下是不是真的写正确了,因为牛客的这个编辑器实在不敢恭维。

--以下为2021年写的答案

这道题最好自己本地手动建库表进行查询测试

我利用navicat建立了和题目一样的表:

  • 表dept_emp:

图片说明

  • 表salaries:

图片说明

>因为我看很多答主的答案中都用到了from_date和to_date字段,我本人是搞不清为何要用这两个字段的,因为我个人觉得也没有什么必要用到这两个字段,所以我采取了下面我的查询方法,主要分两步

  • 先查询出每个部门的编号,和部门中最高的工资,顺带查出员工编号,查询代码为:
select d.emp_no,d.dept_no,max(salary) 
from dept_emp d 
inner join salaries s 
on d.emp_no = s.emp_no group by d.dept_no;

如果你的思路是这样,想一次完成员工编号,部门编号,最高工资的查询,那么很荣幸,你犯了和我一样的错误;因为如果你使用上面的命令进行查询的时候,会惊奇的发现sql报错了:

1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mypsd.d.emp_no' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by, Time: 0.000000s

至于报错原因,请看这位答主的博客:https://www.cnblogs.com/geogre123/p/11177204.html 跟分组后查询应该指定哪些内容输出有关,此处再不赘述。 所以我改正了我的代码,首先,只查询出部门编号和部门中最高的工资:

SELECT d.dept_no,MAX(s.salary) AS maxs
FROM dept_emp d 
INNER JOIN salaries s
on d.emp_no = s.emp_no 
GROUP BY d.dept_no

查询结果为:

图片说明

  • 将上述查询结果作为比一个表,联合dept_emp,salaries表进行多表联查:
SELECT
de.dept_no,de.emp_no,m.maxs
FROM
dept_emp de JOIN salaries sal 
ON
de.emp_no = sal.emp_no 
JOIN
(SELECT d.dept_no,MAX(s.salary) AS maxs
               FROM dept_emp d 
               INNER JOIN salaries s
               ON d.emp_no = s.emp_no 
               GROUP BY d.dept_no) m
ON
m.dept_no = de.dept_no AND m.maxs = sal.salary;

最后我本地查询出正确的结果:

图片说明