MySQL查询需求:找出10月、11月每月第二高薪资的员工
问题分析与修正方案
原SQL的核心问题
- 全局最高薪而非当月最高薪:子查询
select max(sal) from employee_salary取的是全表所有记录的最高薪资,不是对应月份的最高薪,导致排除的不是当月第一高,会返回多个低于全局最高但可能高于当月第二高的员工。 - 关联逻辑不严谨:
natural join依赖两张表的同名字段隐式关联,一旦表结构变更(比如新增同名字段)会引发意外关联,建议显式指定关联条件(如e.empid = s.empid)。 - 代码冗余且分组逻辑不合理:重复编写两次查询用
union拼接,代码冗余;同时group by e.empid搭配max(s.sal)的逻辑无意义(若员工当月只有一条薪资记录,max不会改变结果,还可能因分组字段不完整导致数据异常)。
修正方案
方案一:使用窗口函数(MySQL 8.0+推荐)
利用DENSE_RANK()窗口函数按月份分组并对薪资排名,直接筛选排名为2的记录,逻辑清晰且高效:
SELECT e.empid, e.firstname, e.lastname, e.dateofjoin, s.datesal, s.sal FROM employee e JOIN ( SELECT empid, datesal, sal, -- 按月份分组,薪资降序排名,并列薪资同排名 DENSE_RANK() OVER (PARTITION BY DATE_FORMAT(datesal, '%Y-%m') ORDER BY sal DESC) AS sal_rank FROM employee_salary -- 限定查询2023年10-11月的薪资记录 WHERE datesal BETWEEN '2023-10-01' AND '2023-11-30' ) s ON e.empid = s.empid -- 筛选当月薪资排名第2的员工 WHERE s.sal_rank = 2;
若需要跳过并列名次(比如当月有两个最高薪,下一个直接排第3),可将
DENSE_RANK()替换为RANK()。
方案二:兼容低版本MySQL(无窗口函数)
通过嵌套子查询先获取每个月的最高薪资,再找出当月中低于最高薪的最大值(即第二高),最终关联员工表:
SELECT e.empid, e.firstname, e.lastname, e.dateofjoin, s.datesal, s.sal FROM employee e JOIN employee_salary s ON e.empid = s.empid WHERE -- 限定目标月份 DATE_FORMAT(s.datesal, '%Y-%m') IN ('2023-10', '2023-11') -- 匹配当月第二高薪资 AND s.sal = ( SELECT MAX(sal) FROM employee_salary WHERE DATE_FORMAT(datesal, '%Y-%m') = DATE_FORMAT(s.datesal, '%Y-%m') -- 排除当月最高薪 AND sal < ( SELECT MAX(sal) FROM employee_salary WHERE DATE_FORMAT(datesal, '%Y-%m') = DATE_FORMAT(s.datesal, '%Y-%m') ) );
内容的提问来源于stack exchange,提问作者Vishal Mahendran
相关产品推荐
相关产品推荐

