Laravel Eloquent:获取关联模型超量待处理记录并跳过前2000条
按Prospector分组跳过前2000条待处理Activity的解决方案
要实现每个Prospector单独跳过前2000条待处理Activity,且只保留关联Prospector待处理Activity总数超过2000的记录,核心是利用SQL窗口函数给每个Prospector的Activity分组编号,再筛选符合条件的记录。以下是具体实现:
直接查询方案(一步到位)
通过窗口函数同时计算每个Prospector的待处理Activity总数和单条记录的组内行号,再筛选符合条件的记录:
use Illuminate\Support\Facades\DB; use App\Models\Activity; $targetActivities = Activity::query() // 筛选待处理状态的Activity ->where('status', 'pending') // 追加行号和总数字段 ->select([ '*', // 按Prospector分组,按创建时间升序生成行号(可替换为业务需要的排序字段) DB::raw('ROW_NUMBER() OVER (PARTITION BY prospector_id ORDER BY created_at ASC) AS row_num'), // 计算每个Prospector的待处理Activity总数 DB::raw('COUNT(*) OVER (PARTITION BY prospector_id) AS total_pending') ]) // 筛选总数超2000、且行号大于2000的记录 ->having('total_pending', '>', 2000) ->having('row_num', '>', 2000) ->get();
性能优化方案(先缩范围再查询)
如果数据量较大,可先筛选出符合条件的Prospector ID,再针对这些Prospector查询Activity,减少窗口函数的计算量:
use Illuminate\Support\Facades\DB; use App\Models\Activity; use App\Models\Prospector; // 第一步:获取待处理Activity总数超2000的Prospector ID列表 $qualifiedProspectors = Prospector::query() ->whereHas('activities', function ($query) { $query->where('status', 'pending'); }, '>', 2000) ->pluck('id'); // 第二步:查询这些Prospector的Activity,跳过前2000条 $targetActivities = Activity::query() ->where('status', 'pending') ->whereIn('prospector_id', $qualifiedProspectors) ->select([ '*', DB::raw('ROW_NUMBER() OVER (PARTITION BY prospector_id ORDER BY created_at ASC) AS row_num') ]) ->having('row_num', '>', 2000) ->get();
关键说明
PARTITION BY prospector_id:确保行号按每个Prospector独立计算,避免全局排序导致的错误跳过ORDER BY created_at ASC:可替换为你业务中需要的排序规则(如更新时间、优先级等),保证跳过的是正确的前2000条记录- 窗口函数支持:需要你的数据库版本支持窗口函数(MySQL 8.0+、PostgreSQL、SQL Server等均支持)
内容的提问来源于stack exchange,提问作者Orlando315
相关产品推荐
相关产品推荐

