Laravel子查询中字段排序不生效,不使用join的解决方案问询
问题根因
IN 子句的子查询仅用于值匹配判断,子查询内部的 ORDER BY 不会影响外层查询的结果排序,MySQL 优化器在处理无 LIMIT 的子查询排序时会直接忽略该语句,所以你的排序逻辑没有生效。
可用替代方案(无JOIN实现)
方案1:先查排序后的Phone列表,外层按列表顺序匹配
你可以先独立完成numbers表的筛选、排序逻辑,取出按quality排好序的phone数组,再通过FIELD函数让外层查询按照数组顺序返回结果,全程不需要JOIN:
// 第一步:取出符合条件且按quality升序排列的phone数组 $validPhones = \DB::table('numbers') ->select('phone') ->whereNull('client_group_id') ->whereNotIn('id', function($query) use ($request) { $query->select('number_push_logs.number_id') ->from('number_push_logs') ->where('number_push_logs.client_group_id', $request['client_group']); }) ->when(!empty($request['min_quality']), function($q) use ($request) { $q->where('quality', '>=', $request['min_quality']); }) ->when(!empty($request['max_quality']), function($q) use ($request) { $q->where('quality', '<=', $request['max_quality']); }) ->when(!empty($request['number_type']), function($q) use ($request) { $q->whereIn('number_type_id', $request['number_type']); }) ->when(!empty($request['contact_status']), function($q) use ($request) { $q->where('contact_status_id', $request['contact_status']); }) ->orderBy('quality', 'asc') ->pluck('phone') ->toArray(); // 第二步:匹配phone并按数组顺序排序 $res = NumberUpload::query() ->when(!empty($request['domain']), function($q) use ($request) { $q->whereIn('domain_id', $request['domain']); }) ->whereIn('phone', $validPhones) ->orderByRaw(\DB::raw('FIELD(phone, ' . implode(',', array_fill(0, count($validPhones), '?')) . ')'), $validPhones) ->limit(5) ->get();
方案2:子查询加LIMIT保留排序逻辑(适合单查询场景)
如果不想拆分两次查询,可以给子查询加一个足够大的LIMIT,让MySQL不忽略子查询的排序逻辑,再在外层关联排序:
$model = NumberUpload::query() ->when(!empty($request['domain']), fn($q) => $q->whereIn('domain_id', $request['domain'])) ->whereIn('phone', function($query) use ($request){ $query->select('phone') ->from('numbers') ->whereNull('numbers.client_group_id') ->whereNotIn('id', fn($q) => $q->select('number_push_logs.number_id') ->from('number_push_logs') ->where('number_push_logs.client_group_id',$request['client_group']) ) ->when(!empty($request['min_quality']), fn($q) => $q->where('numbers.quality', '>=', $request['min_quality'])) ->when(!empty($request['max_quality']), fn($q) => $q->where('numbers.quality', '<=', $request['max_quality'])) ->when(!empty($request['number_type']), fn($q) => $q->whereIn('numbers.number_type_id', $request['number_type'])) ->when(!empty($request['contact_status']), fn($q) => $q->where('numbers.contact_status_id', $request['contact_status'])) ->orderBy('numbers.quality', 'asc') ->limit(10000); // 加足够大的LIMIT避免排序被优化器忽略 }) ->orderByRaw('quality asc') ->limit(5) ->get();
内容的提问来源于stack exchange,提问作者Jazz
相关产品推荐
相关产品推荐

