SQL统计5月预订天数 跨月日期计算错误问题求解
核心需求与原有实现问题
需求为统计2022年5月时间范围内各房间的累计预订总天数,筛选累计预订天数小于21天的房间。
原有SQL实现存在以下缺陷:
- 分支判断仅覆盖3类跨期场景,遗漏「预订完全在5月前结束」「预订完全在5月后开始」「预订时段横跨整个5月(开始早于5月1日、结束晚于5月31日)」三类场景,统计覆盖不全
- 未对和5月完全无交集的预订记录做过滤,直接计算日期差会出现负数值,导致非5月时段被错误计入统计
- 使用逗号隐式连表、
SELECT *配合GROUP BY的写法不符合SQL规范,易返回非预期的字段值
统一统计逻辑
无需编写多分支CASE判断,通过统一的日期截断+非负校验即可覆盖所有预订场景:
- 单条预订的统计起点:取预订实际开始时间、5月1日零点二者的较大值
- 单条预订的统计终点:取预订实际结束时间、5月31日23点59分59秒二者的较小值
- 单条预订贡献的5月预订天数:仅当统计终点晚于起点时计算日期差,否则记为0(完全不落在5月的预订直接计0,彻底避免负数问题)
- 按房间维度聚合所有预订的有效天数,筛选总天数小于21的房间即可
修正后SQL代码
SELECT p.id_room, -- 可按需补充rooms表需要返回的其他字段,禁止直接写SELECT *配合GROUP BY SUM( GREATEST(0, DATEDIFF( LEAST(r.end_date, '2022-05-31 23:59:59'), GREATEST(r.start_date, '2022-05-01 00:00:00') )) ) AS may_total_book_days FROM rooms p INNER JOIN bookings r ON p.id_room = r.id_room GROUP BY p.id_room HAVING may_total_book_days < 21;
场景覆盖验证
修正后的逻辑可以覆盖所有可能的预订时段场景:
- 预订完全落在5月内:直接计算实际起止点的日期差,结果准确
- 预订开始于5月前、结束于5月内:起点自动截断为5月1日,计算到实际结束日的差值
- 预订开始于5月内、结束于5月后:终点自动截断为5月31日,计算从实际开始日的差值
- 预订时段横跨整个5月:起止点自动截断为5月1日、5月31日,统计整月有效天数
- 预订完全在5月前结束/完全在5月后开始:截断后终点早于起点,日期差为负,通过
GREATEST(0, ...)强制记为0,不会对统计结果造成干扰
提示:如果业务规则中预订天数计算需包含离店当日(例:5月1日入住、5月2日离店计为2天),可在DATEDIFF计算结果后+1适配规则。
内容的提问来源于stack exchange,提问作者LLager
相关产品推荐
相关产品推荐

