Laravel SQL查询无法正确展示午夜时段轮渡班次的技术问题咨询
解决轮渡时刻表午夜班次查询问题
看起来你遇到的核心问题是时间比较的逻辑漏洞:当当前时间处于夜间(比如22:00之后),午夜时段的班次(如1:30am)的时间字符串会比当前时间小,导致原查询里的whereTime('departure_time', '>', 当前时间)直接把这些班次排除了,但实际上这些班次属于第二天,是当前时间之后的下一班次。
问题拆解
举个具体例子:当前时间是23:00:00,数据库里的班次时间为01:30:00、06:30:00。用你原来的查询会因为01:30:00 < 23:00:00过滤掉午夜班次,要么返回空,要么直接展示早班,但用户实际需要的下一班是午夜的01:30:00。
优化解决方案:分场景处理时间查询
我们需要调整查询逻辑,覆盖两种实际场景:
- 当前时间之后还有当天的班次 → 取这些班次里每个轮渡的最早一班
- 当前时间之后没有当天的班次 → 自动取第二天最早的班次(即午夜时段的班次)
下面是适配需求的Laravel查询代码:
$currentTime = Carbon::now()->toTimeString(); $nextFerries = DB::table('ferries') ->whereIn('schedule_type', ['Weekday']) ->where('terminal_name', $terminal_name) // 核心逻辑:要么取当前时间之后的班次,要么取那些当前时间后无班次的轮渡的所有班次 ->where(function ($query) use ($currentTime) { $query->whereTime('departure_time', '>', $currentTime) ->orWhereNotExists(function ($subQuery) use ($currentTime) { $subQuery->select(DB::raw(1)) ->from('ferries as f2') ->whereColumn('f2.ferry_name', 'ferries.ferry_name') ->whereIn('f2.schedule_type', ['Weekday']) ->where('f2.terminal_name', $terminal_name) ->whereTime('f2.departure_time', '>', $currentTime); }); }) // 排序规则:先展示当前时间后的班次,再展示午夜班次;同轮渡下按时间升序 ->orderByRaw("CASE WHEN departure_time > ? THEN 0 ELSE 1 END, departure_time", [$currentTime]) // 按轮渡名称分组,确保每个轮渡只返回下一班次 ->groupBy('ferry_name') ->get() ->all();
代码逻辑说明
where闭包:通过orWhereNotExists判断,如果某个轮渡在当前时间之后没有任何班次,就把它的所有班次纳入查询范围,避免遗漏午夜班次orderByRaw:用CASE表达式优先排序当前时间之后的班次,再排午夜班次,确保展示顺序符合用户实际需求groupBy:保证每个轮渡只返回最近的下一班次
额外提醒
- 确保你的
departure_time字段是数据库的time类型,这样whereTime才能正确进行时间比较 - 如果需要支持多调度类型(比如周末、节假日),只需调整
whereIn('schedule_type', [...])的参数即可
内容的提问来源于stack exchange,提问作者Navy
相关产品推荐
相关产品推荐

