SQL200. 查找最晚入职员工的所有信息
题目描述
查找 employees 表中最晚入职员工的所有信息。
表结构
表:employees
CREATE TABLE employees (
emp_no INT(11) PRIMARY KEY COMMENT '员工编号',
birth_date DATE COMMENT '出生日期',
first_name VARCHAR(14) COMMENT '名',
last_name VARCHAR(16) COMMENT '姓',
gender CHAR(1) COMMENT '性别(M/F)',
hire_date DATE COMMENT '入职日期'
);
| 字段名 | 类型 | 说明 |
|---|---|---|
| emp_no | INT(11) | 员工编号,主键 |
| birth_date | DATE | 出生日期 |
| first_name | VARCHAR(14) | 名 |
| last_name | VARCHAR(16) | 姓 |
| gender | CHAR(1) | 性别(M/F) |
| hire_date | DATE | 入职日期 |
示例数据
employees
| emp_no | birth_date | first_name | last_name | gender | hire_date |
|---|---|---|---|---|---|
| 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 |
| 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 |
| 10003 | 1959-12-03 | Parto | Bamford | M | 1986-08-28 |
| 10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 |
预期输出
| emp_no | birth_date | first_name | last_name | gender | hire_date |
|---|---|---|---|---|---|
| 10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 |
最晚入职日期为 1994-09-15,对应员工 10008。
解题思路
第一步:理解需求
题目要求找到"最晚入职"的员工。所谓"最晚",即 hire_date 字段中的最大值。找到这个最大日期后,再返回该员工的所有信息。
第二步:分析表结构
只有一张 employees 表,所有需要的信息都在这张表里。但查询需要分两步:
- 找出最大的
hire_date - 根据该日期查询完整记录
第三步:确定 SQL 方案
有三种常见的解决思路:
- 子查询:
WHERE hire_date = (SELECT MAX(hire_date) FROM employees) - ORDER BY + LIMIT:先排序再取第一条
- 窗口函数:
ROW_NUMBER() OVER (ORDER BY hire_date DESC)
第四步:编写并验证 SQL
子查询方式最直观,也是本题的标准解法。需要注意的是,如果存在多人同一天最晚入职,子查询和窗口函数可以返回多人,而 LIMIT 1 只会返回一人。
完整 SQL 实现
-- 方法一:子查询 + MAX() —— 最直观的写法
SELECT *
FROM employees
WHERE hire_date = (SELECT MAX(hire_date) FROM employees);
-- 方法二:ORDER BY + LIMIT —— 简洁写法
-- 注意:如果有多人同一天最晚入职,只返回一人
SELECT *
FROM employees
ORDER BY hire_date DESC
LIMIT 1;
-- 方法三:窗口函数 —— 如果有多人同一天最晚入职,也能全部返回
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY hire_date DESC) AS rn
FROM employees
)
SELECT * FROM ranked WHERE rn = 1;
解法详解
方法一:子查询 + MAX()(推荐)
SELECT * FROM employees
WHERE hire_date = (SELECT MAX(hire_date) FROM employees);
执行过程:
- 内层子查询
(SELECT MAX(hire_date) FROM employees)先执行,返回1994-09-15 - 外层查询等价于
WHERE hire_date = '1994-09-15',返回所有该日期入职的员工
优点:逻辑清晰,能返回所有最晚入职的员工(即使有多人同一天入职)。
方法二:ORDER BY + LIMIT
SELECT * FROM employees
ORDER BY hire_date DESC
LIMIT 1;
执行过程:
- 按
hire_date降序排列,最晚入职的员工排在最前面 LIMIT 1只取第一条
优点:写法简洁。
缺点:如果多人同一天最晚入职,只能返回其中一人(通常是 emp_no 最小的那个,取决于数据库默认排序)。
方法三:窗口函数
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY hire_date DESC) AS rn
FROM employees
)
SELECT * FROM ranked WHERE rn = 1;
执行过程:
ROW_NUMBER()为每一行按hire_date降序分配行号,最晚入职的员工获得rn = 1- 外层查询筛选
rn = 1的记录
优点:功能强大,可以灵活处理并列情况(将 ROW_NUMBER 换成 RANK 或 DENSE_RANK 可实现不同并列逻辑)。
缺点:MySQL 8.0+ 才支持窗口函数。
知识点总结
1. 聚合函数 MAX()
MAX(column) 返回某列的最大值。常用于:
- 找最新日期:
MAX(hire_date) - 找最高分数:
MAX(score) - 找最大金额:
MAX(amount)
2. 子查询(Subquery)
子查询是嵌套在另一个查询中的查询。本题中子查询出现在 WHERE 子句中,用于提供比较值。
SELECT * FROM table
WHERE column = (SELECT MAX(column) FROM table);
3. ORDER BY + LIMIT
SELECT * FROM table
ORDER BY column DESC -- 降序(从大到小)
LIMIT n; -- 只返回前 n 条
这是获取"Top N"记录的经典写法。
易错点总结
1. LIMIT 1 遗漏多人并列的情况
如果 1994-09-15 有 3 个员工同时入职,使用 LIMIT 1 只会返回其中一人。如果题目要求返回所有最晚入职的员工,应使用子查询方式。
2. 混淆 LIMIT 和 TOP
- MySQL / PostgreSQL 使用
LIMIT n - SQL Server 使用
TOP n - Oracle 使用
FETCH FIRST n ROWS ONLY
牛客网使用 MySQL,所以用 LIMIT。
3. 忘记考虑 NULL 值
如果 hire_date 列存在 NULL,MAX(hire_date) 会忽略 NULL 值返回最大非 NULL 值,这是符合预期的行为。
扩展思考
- 如何查找最早入职的员工? 将
MAX改为MIN,或将DESC改为ASC。 - 如何查找入职第二晚的员工? 使用窗口函数
ROW_NUMBER(),筛选rn = 2。 - 性能考虑:
hire_date列如果有索引,子查询和 ORDER BY 都能利用索引快速定位。