Laravel Eloquent多whereHas关联查询实现公交线路站点顺序校验
实现方案
你可以直接把原生SQL的EXISTS校验逻辑平移到Eloquent查询中,同时关联places表直接通过slug匹配地点,完整代码如下:
use Illuminate\Support\Facades\DB; $buses = Bus::whereHas('route', function ($query) use ($from, $to) { $query->whereExists(function ($startQuery) use ($from, $to) { $startQuery->select(DB::raw(1)) ->from('route_locations as start_loc') // 关联出发地地点表匹配slug ->join('places as start_place', 'start_loc.place_id', '=', 'start_place.id') ->whereColumn('start_loc.route_id', 'routes.id') ->where('start_place.slug', $from) ->where('start_loc.end', 0) // 校验存在顺序更靠后的目的地站点 ->whereExists(function ($endQuery) use ($to) { $endQuery->select(DB::raw(1)) ->from('route_locations as end_loc') ->join('places as end_place', 'end_loc.place_id', '=', 'end_place.id') ->whereColumn('end_loc.route_id', 'start_loc.route_id') ->where('end_place.slug', $to) ->where('end_loc.start', 0) ->whereColumn('end_loc.order', '>', 'start_loc.order'); }); }); }) // 预加载关联数据,视图层可直接调用关联属性 ->with(['route.locations.place']) ->get();
注意事项
order是SQL保留关键字,如果运行时报语法错误,需要将end_loc.order和start_loc.order替换为DB::raw('order')做转义。
如果需要优化查询性能,建议新增三个索引:
- places表slug字段加唯一索引
- route_locations表加(route_id, place_id, order)联合索引
内容的提问来源于stack exchange,提问作者Adriaan
相关产品推荐
相关产品推荐

