
本文详解如何通过 sql 查询实现房间可用性搜索,重点解决日期范围重叠判断逻辑错误,提供 codeigniter 框架下的正确 join 与 where 条件写法,并附可运行示例及关键注意事项。
本文详解如何通过 sql 查询实现房间可用性搜索,重点解决日期范围重叠判断逻辑错误,提供 codeigniter 框架下的正确 join 与 where 条件写法,并附可运行示例及关键注意事项。
在酒店、公寓或会议室预订系统中,“按日期范围搜索可用房间”是一个核心功能。其本质是:找出所有未被任何现有订单完全覆盖(即无时间重叠)的房间。常见误区是将日期冲突逻辑写反,或错误地在 WHERE 中对 LEFT JOIN 的右表字段施加条件,导致关联失效(如 b.brId IS NULL 被误用)。
✅ 正确的日期重叠判断逻辑
两个日期区间 [start1, end1] 和 [start2, end2] 不重叠 的充要条件是:
end1 = end2
因此,存在重叠 的条件为:
end1 > start2 AND start1
在本场景中,用户输入的查询区间为 [$start, $end)(注意:通常 checkout 是入住次日,故区间为左闭右开),需排除所有满足 bCheckin $start 的已预订记录。
✅ 修正后的 CodeIgniter 查询函数(推荐写法)
function search($room, $start, $end) {
// 注意:$start 和 $end 应为 Y-m-d 格式字符串,且已通过 escape 或绑定参数防护 SQL 注入
$this->db->select('r.rId as id,
r.rName as name,
r.rCapacity as capacity,
b.bCheckin as checkin,
b.bCheckout as checkout,
b.bBookingTime as bookingtime');
$this->db->from('room r');
// 关键:使用 LEFT JOIN + ON 条件过滤预订,而非 WHERE 过滤
$this->db->join('booking b', 'b.brId = r.rId
AND b.bCheckin "' . $start . '"', 'left');
// 筛选房间名(模糊匹配)
$this->db->like('r.rName', $room);
// 关键:仅保留“无冲突预订”的房间 → 即 b.brId 为 NULL 的行
$this->db->where('b.brId IS NULL');
return $this->db->get()->result_array();
}
⚠️ 原代码主要问题解析
- ❌ where('bCheckout' > $start AND 'bCheckin'
- ❌ where('brId', NULL):CodeIgniter 中应写为 where('brId IS NULL') 或 where('brId', null, false)。
- ❌ 原生 SQL 中 WHERE 子句重复、表别名不一致(b.orderRuangan 字段不存在)、日期逻辑颠倒(NOT ($end >= ...) 表达不准确)。
✅ 更安全的原生 SQL(带参数化占位符示意)
SELECT r.rId AS id,
r.rName AS name,
r.rCapacity AS capacity,
b.bCheckin AS checkin,
b.bCheckout AS checkout,
b.bBookingTime AS bookingtime
FROM room r
LEFT JOIN booking b
ON b.brId = r.rId
AND b.bCheckin ? -- $start
WHERE r.rName LIKE ?
AND b.brId IS NULL;
✅ 推荐使用 $this->db->query($sql, [$end, $start, "%{$room}%"]) 执行,避免 SQL 注入。
? 验证逻辑的小技巧
假设某房间有预订:checkin='2025-06-10', checkout='2025-06-15'
- 用户搜 2025-06-01 → 2025-06-05:✅ 无重叠 → 房间显示
- 用户搜 2025-06-12 → 2025-06-14:❌ 重叠 → 房间隐藏
- 用户搜 2025-06-15 → 2025-06-18:✅ 边界不重叠(若 checkout 为入住次日,则 2025-06-15 可入住)→ 显示
✅ 总结
- 日期重叠判断务必使用 bCheckin $start;
- 利用 LEFT JOIN 的 ON 子句提前过滤冲突预订,再用 WHERE b.brId IS NULL 筛出干净房间;
- 始终对用户输入执行转义或参数化查询;
- 在真实项目中,建议补充索引:booking(brId, bCheckin, bCheckout) 提升查询性能。
掌握此模式后,即可轻松扩展为多房间批量检查、按容量/价格筛选等高级功能。









