MySQL查询需求:按person_id获取符合时间范围的最大id记录
问题分析与解决方案
表结构与数据
people表结构及数据如下:
| id | person_id | meeting_time |
|---|---|---|
| 1 | 21 | 123456 |
| 2 | 21 | 123457 |
| 3 | 21 | 123456 |
| 4 | 22 | 123470 |
| 5 | 21 | 0 |
| 6 | 21 | 123472 |
核心需求
- 仅返回
person_id的所有记录的meeting_time都处于123451~123460之间的用户记录;若该用户存在任何一条超出此范围的记录,则不返回该用户的任何行。 - 对符合条件的用户,返回其在时间范围内的记录中
id最大的那条(排除id小但meeting_time大的记录,如id=2的行)。
当前查询的问题
你当前的查询没有分组,且未过滤存在超出范围记录的person_id:
SELECT MAX(`id`) AS `id`, `person_id`, `meeting_time` FROM `people` WHERE `meeting_time` > 123451 AND `meeting_time` < 123460 ORDER BY `id` DESC
- MySQL 5.5中无
GROUP BY时会隐式聚合,person_id和meeting_time会随机取符合WHERE条件的某一行值,导致返回id=2的记录而非id=3。 - 未过滤存在超出时间范围记录的
person_id(如id=5、6的行属于person_id=21),所以新增id=6后仍会返回该用户的记录。
解决方案(适配MySQL 5.5)
使用嵌套子查询先筛选出符合条件的用户,再找到每个用户的最大id对应的记录:
SELECT p.* FROM people p -- 关联筛选出所有记录都在时间范围内的person_id INNER JOIN ( SELECT person_id FROM people GROUP BY person_id HAVING MIN(meeting_time) >= 123451 AND MAX(meeting_time) <= 123460 ) valid_persons ON p.person_id = valid_persons.person_id -- 关联找到每个符合条件用户的最大id INNER JOIN ( SELECT person_id, MAX(id) AS max_id FROM people WHERE meeting_time BETWEEN 123451 AND 123460 GROUP BY person_id ) max_ids ON p.person_id = max_ids.person_id AND p.id = max_ids.max_id;
逻辑说明
- 第一个子查询
valid_persons:通过GROUP BY和HAVING子句,筛选出所有记录的meeting_time都在123451~123460之间的person_id。 - 第二个子查询
max_ids:找到每个符合时间范围的person_id对应的最大id。 - 最终通过两次关联,获取到符合所有条件的完整记录。
验证结果
- 新增id=6后,person_id=21存在超出范围的记录,查询返回空,符合需求。
- 若移除id=5和id=6,查询会返回person_id=21的id=3的记录,符合要求。
内容的提问来源于stack exchange,提问作者Lanexbg
相关产品推荐
相关产品推荐

