跳到主要内容

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_noINT(11)员工编号,主键
birth_dateDATE出生日期
first_nameVARCHAR(14)
last_nameVARCHAR(16)
genderCHAR(1)性别(M/F)
hire_dateDATE入职日期

示例数据

employees

emp_nobirth_datefirst_namelast_namegenderhire_date
100011953-09-02GeorgiFacelloM1986-06-26
100021964-06-02BezalelSimmelF1985-11-21
100031959-12-03PartoBamfordM1986-08-28
100081958-02-19SaniyaKalloufiM1994-09-15

预期输出

emp_nobirth_datefirst_namelast_namegenderhire_date
100081958-02-19SaniyaKalloufiM1994-09-15

最晚入职日期为 1994-09-15,对应员工 10008


解题思路

第一步:理解需求

题目要求找到"最晚入职"的员工。所谓"最晚",即 hire_date 字段中的最大值。找到这个最大日期后,再返回该员工的所有信息。

第二步:分析表结构

只有一张 employees 表,所有需要的信息都在这张表里。但查询需要分两步:

  1. 找出最大的 hire_date
  2. 根据该日期查询完整记录

第三步:确定 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);

执行过程

  1. 内层子查询 (SELECT MAX(hire_date) FROM employees) 先执行,返回 1994-09-15
  2. 外层查询等价于 WHERE hire_date = '1994-09-15',返回所有该日期入职的员工

优点:逻辑清晰,能返回所有最晚入职的员工(即使有多人同一天入职)。

方法二:ORDER BY + LIMIT

SELECT * FROM employees
ORDER BY hire_date DESC
LIMIT 1;

执行过程

  1. hire_date 降序排列,最晚入职的员工排在最前面
  2. 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;

执行过程

  1. ROW_NUMBER() 为每一行按 hire_date 降序分配行号,最晚入职的员工获得 rn = 1
  2. 外层查询筛选 rn = 1 的记录

优点:功能强大,可以灵活处理并列情况(将 ROW_NUMBER 换成 RANKDENSE_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 都能利用索引快速定位。

相关题目

加载评论中...