MySQL多表查询:筛选指定时间段未被预订的车辆
筛选指定时间段内未被预订的车辆
你需要调整现有查询,加入对assigned表的时间冲突检测,这样就能过滤掉在目标时间段(1527804060 至 1527811320)内已经被分配的车辆。
核心逻辑
判断车辆是否可用的关键是:该车辆没有任何一条assigned记录的时间段和目标预订时间段重叠。时间段重叠的判定条件是:
assigned_start < 目标结束时间 AND assigned_end > 目标开始时间
这个条件能覆盖所有可能的重叠场景(比如目标时间段包含已分配时段、被包含、或者部分重叠)。
优化后的查询代码
这里推荐用NOT EXISTS子查询来实现,逻辑清晰且性能表现不错:
foreach ($sid as $key => $value) { // 定义目标预订的起止时间 $targetStart = 1527804060; $targetEnd = 1527811320; $vehicle->rowQuery(" SELECT s.supplierName, v.vid, v.vehicleName, v.noOfSeat, v.seatBooked, v.type FROM vehicle AS v LEFT JOIN supplier AS s ON v.sid = s.sid RIGHT JOIN driver AS d ON d.vid = v.vid WHERE v.sid = $value AND NOT EXISTS ( SELECT 1 FROM assigned AS a WHERE a.vid = v.vid AND a.assigned_start < $targetEnd AND a.assigned_end > $targetStart ) ORDER BY v.vid DESC "); }
备选写法:LEFT JOIN + IS NULL
如果你更习惯用JOIN的方式实现,也可以这样写:
foreach ($sid as $key => $value) { $targetStart = 1527804060; $targetEnd = 1527811320; $vehicle->rowQuery(" SELECT s.supplierName, v.vid, v.vehicleName, v.noOfSeat, v.seatBooked, v.type FROM vehicle AS v LEFT JOIN supplier AS s ON v.sid = s.sid RIGHT JOIN driver AS d ON d.vid = v.vid LEFT JOIN assigned AS a ON a.vid = v.vid AND a.assigned_start < $targetEnd AND a.assigned_end > $targetStart WHERE v.sid = $value AND a.asgid IS NULL ORDER BY v.vid DESC "); }
重要提示
- 防止SQL注入:直接把变量拼进SQL语句存在注入风险,建议使用参数化查询(比如PDO的
prepare+bindParam,或者你所用框架的参数绑定功能)来替代这种写法。 - 验证时间逻辑:可以先单独测试子查询部分,确认它能正确找出被占用的车辆,再整合到主查询中。
按照这个逻辑,查询会自动排除vid=14和15的车辆,只返回你需要的vid=13、16、17、18的车辆。
内容的提问来源于stack exchange,提问作者user8625234
相关产品推荐
相关产品推荐

