在员工薪酬管理相关的业务场景中,经常需要统计员工最近的两次晋升日期以及对应的工资额,这类需求可以通过SQL的排序和取数逻辑快速实现。下面先介绍模拟的业务场景表结构,再给出两种常用的查询方案。

模拟数据表结构
我们首先创建一张员工晋升记录表employee_promotion,用于存储员工的晋升相关信息,表结构如下:
-- 创建员工晋升记录表
CREATE TABLE employee_promotion (
id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT NOT NULL COMMENT '员工ID',
promotion_date DATE NOT NULL COMMENT '晋升日期',
salary DECIMAL(10,2) NOT NULL COMMENT '晋升后工资额',
INDEX idx_emp_date (emp_id, promotion_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据
INSERT INTO employee_promotion (emp_id, promotion_date, salary) VALUES
(1001, '2020-03-01', 8000.00),
(1001, '2021-06-15', 9500.00),
(1001, '2023-01-10', 12000.00),
(1001, '2024-05-20', 15000.00),
(1002, '2021-02-01', 7500.00),
(1002, '2023-04-12', 11000.00),
(1003, '2022-07-01', 9000.00);
方案一:使用窗口函数查询
如果数据库版本支持窗口函数(如MySQL 8.0+、PostgreSQL、SQL Server等),可以使用ROW_NUMBER()窗口函数按员工分组、按晋升日期降序排序,再筛选出排名前2的记录,即可得到每位员工最近的两次晋升信息。
SELECT
emp_id,
promotion_date,
salary
FROM (
SELECT
emp_id,
promotion_date,
salary,
-- 按员工分组,晋升日期降序排序,生成序号
ROW_NUMBER() OVER (PARTITION BY emp_id ORDER BY promotion_date DESC) AS rn
FROM employee_promotion
) t
-- 筛选最近的两次晋升记录,序号1是最近一次,序号2是上一次
WHERE rn <= 2
ORDER BY emp_id, promotion_date DESC;
上述查询的执行逻辑是:子查询中先对每个员工的晋升记录按日期从新到旧排序,给每条记录标记序号,外层查询只取序号小于等于2的记录,最终得到每个员工最近的两次晋升日期和工资额。如果员工晋升次数不足2次,会返回实际存在的所有晋升记录。
方案二:使用自连接查询
如果数据库版本不支持窗口函数,可以使用自连接的方式实现。核心思路是找到每个晋升记录之后是否存在至少2条更晚的晋升记录,符合条件的就是最近的两次晋升。
SELECT
a.emp_id,
a.promotion_date,
a.salary
FROM employee_promotion a
-- 自连接匹配更晚的晋升记录
LEFT JOIN employee_promotion b
ON a.emp_id = b.emp_id
AND a.promotion_date < b.promotion_date
-- 按员工和当前晋升日期分组,统计更晚的晋升记录数量
GROUP BY a.emp_id, a.promotion_date, a.salary
-- 更晚的晋升记录数量小于2,说明当前记录是最近的两次之一
HAVING COUNT(b.id) < 2
ORDER BY a.emp_id, a.promotion_date DESC;
这个方法的逻辑是:对于每条晋升记录a,统计比它晋升日期更晚的记录数量,如果更晚的记录数小于2,说明a要么是最近一次晋升,要么是上一次晋升,正好符合要求。不过自连接的方式在数据量较大时性能会比窗口函数差一些。
两种方案对比
我们可以通过下表对比两种方案的适用场景和特点:
| 方案 | 适用数据库 | 性能 | 实现复杂度 |
|---|---|---|---|
| 窗口函数法 | 支持窗口函数的数据库版本 | 较高,逻辑清晰 | 低,代码简洁 |
| 自连接法 | 所有支持标准SQL的数据库 | 较低,数据量大时耗时增加 | 较高,需要理解分组统计逻辑 |
实际业务中可以根据数据库版本和数据量选择合适的方案,优先推荐窗口函数法,可读性和性能都更有优势。