Laravel已执行查询追加join及一对多关联重复问题解决方案问询
Laravel查询问题解决方案
1. 已执行完成的查询能否追加语句
答案是不能。一旦你调用了get()、first()这类触发SQL执行的方法,查询构造器就会向数据库发送请求并返回Collection集合/模型实例对象,此时已经是结果数据,无法再追加新的查询条件。如果需要调整查询,必须在调用执行方法之前操作查询构造器实例。
2. 一对多关联join导致数据重复的解决方案
你当前遇到的重复问题是一对多join产生笛卡尔积的典型表现,最优解决方式是放弃直接join一对多的tolls表,改用Laravel自带的关联预加载功能,既不会产生重复数据,还能将tolls数据以数组形式挂载到对应关联对象下,完全符合你的需求。
实现步骤
- 先在
Route模型中定义和tolls的一对多关联:
// app/Models/Route.php public function tolls() { // 第二个参数是tolls表关联route的外键,第三个参数是route表的主键 return $this->hasMany(Toll::class, 'route_id', 'uuid'); }
- 修改原有查询代码,去掉
tolls的join,改用with预加载关联:
$results = $this->model::leftjoin('Route', 'Route.RouteID', 'Trip.RouteID') ->leftjoin('ReferenceTrip', 'ReferenceTrip.ReferenceTripID', 'Trip.ReferenceTripID') ->leftjoin('route', 'route.uuid','ReferenceTripGroup.route_id') ->with('route.tolls') // 预加载关联的所有tolls数据 ->get(); // 替换为first()也完全兼容 // ->first();
该方案优势
- 完全避免主表数据重复,查询返回的主数据行数和不加tolls关联时一致
- 所有关联的
tolls数据会以数组形式挂载到每条结果的route->tolls属性下,无需额外处理 - 性能优于join方案,不会产生冗余数据传输
如果确实需要用join实现,也可以通过分组聚合处理重复,不过适配成本更高,仅做参考:
$results = $this->model::leftjoin('Route', 'Route.RouteID', 'Trip.RouteID') ->leftjoin('ReferenceTrip', 'ReferenceTrip.ReferenceTripID', 'Trip.ReferenceTripID') ->leftjoin('route', 'route.uuid','ReferenceTripGroup.route_id') ->leftjoin('tolls', 'tolls.route_id', 'route.uuid') ->select('Trip.*', 'Route.*', 'ReferenceTrip.*', 'route.*', \DB::raw('GROUP_CONCAT(tolls.field_name SEPARATOR ",") as toll_fields')) ->groupBy('Trip.主键字段') // 需按主表唯一字段分组,同时需匹配数据库分组规则配置 ->get();
内容的提问来源于stack exchange,提问作者TheGeeky
相关产品推荐
相关产品推荐

