MySQL查询实现用户预约时段的时间重叠校验方法
校验用户预约时间冲突的MySQL查询方案
刚好做过类似的预约系统,这个时间冲突校验的核心是正确判断两个时间段是否重叠,我给你写一套实用的查询方案,附带详细解释:
核心逻辑:如何判断时间重叠
两个时间段[开始1, 结束1]和[开始2, 结束2]存在重叠的充要条件是:开始1 < 结束2 且 结束1 > 开始2
这个规则能覆盖所有重叠场景(包含、部分重叠),首尾相接的时段不算重叠,完全符合预约系统的常规需求。
具体查询实现
假设你的表结构是:
sessions:id(场次ID)、title、session_date(日期,DATE类型)、start_time(开始时间,TIME类型)、duration(时长,分钟数)calendar:user_id(用户ID)、session_date(日期)、start_time(已占用时段开始)、end_time(已占用时段结束)
方式1:分步查询(更易理解调试)
先获取目标场次的完整时间范围,再校验冲突:
-- 1. 定义要校验的用户ID和目标场次ID SET @check_user_id = 1001; SET @target_session_id = 2001; -- 2. 获取目标场次的时间范围,计算出结束时间 SELECT session_date, start_time, ADDTIME(start_time, SEC_TO_TIME(duration * 60)) AS session_end_time INTO @target_date, @target_start, @target_end FROM sessions WHERE id = @target_session_id; -- 3. 检查该用户是否有冲突的已预约记录 SELECT COUNT(*) AS conflict_count FROM calendar WHERE user_id = @check_user_id AND session_date = @target_date -- 不同日期直接跳过校验 AND start_time < @target_end -- 已占用时段开始早于目标场次结束 AND end_time > @target_start; -- 已占用时段结束晚于目标场次开始
如果conflict_count > 0,说明用户该时段已有预约,不能重复预订;等于0则可以正常预约。
方式2:合并为单查询(更简洁高效)
不用临时变量,直接关联表完成校验:
SELECT COUNT(*) AS conflict_count FROM calendar c JOIN sessions s ON c.session_date = s.session_date WHERE c.user_id = 1001 -- 替换为实际用户ID AND s.id = 2001 -- 替换为要预订的场次ID AND c.start_time < ADDTIME(s.start_time, SEC_TO_TIME(s.duration * 60)) AND c.end_time > s.start_time;
注意事项
- 字段类型适配:如果你的时间字段是
DATETIME(日期+时间),那更简单,直接用DATE_ADD(s.start_datetime, INTERVAL s.duration MINUTE)计算结束时间,然后去掉session_date的判断,直接比较两个datetime范围即可。 - 索引优化:给
calendar表添加复合索引(user_id, session_date),能大幅提升冲突校验的查询速度,尤其是用户量和预约记录多的时候。 - 边界处理:如果业务允许“首尾相接”的预约(比如上一场10:00结束,下一场10:00开始),那把判断条件里的
<和>改成<=和>=即可,根据你的业务规则灵活调整。
内容的提问来源于stack exchange,提问作者BeingExpert
相关产品推荐
相关产品推荐

