Laravel 8中如何使用Eloquent实现左连接?关联查询分组异常问题
问题排查
1. 关联关系定义错误
你写反了两个模型的关联逻辑:
- 父表
CommonUnit对应多个子表Item记录,应该定义hasMany关联,而非belongsTo belongsTo是子模型用来关联父模型的方法,第二个参数是子模型里的外键字段名
你的外键逻辑也搞反了:子表Item才会存储父表的外键id_common_unit(你代码里的item_id_common_unit应该就是这个字段)
2. 预加载with()无法实现SQL层面的左连接分组
with()是Laravel的预加载机制,本质是执行两次独立查询:
- 先查
CommonUnit表的所有符合条件的记录 - 再用第一步拿到的
id_common_unit集合去查Item表,最后在PHP层面把关联数据匹配到父结果上
你在主表查询上加的groupBy只会作用于第一次的CommonUnit查询,完全不会影响关联的Item数据的分组逻辑,自然达不到你要的连表分组效果。
修正方案
第一步:修正关联定义
修改CommonUnit.php的关联方法:
public function items() { // 第一个参数:子模型类,第二个参数:子表的外键字段,第三个参数:父表的主键字段 return $this->hasMany(\App\Item::class, 'item_id_common_unit', 'id_common_unit'); }
如果你的Item表存储父表外键的字段是id_common_unit,把第二个参数改成id_common_unit即可。
第二步:选择适合的查询方式
方案A:保留预加载,直接在PHP层面处理分组
如果不需要SQL层面连表,只是要按id_common_unit聚合关联的Item数据,直接去掉主查询的groupBy即可,预加载会自动把对应Item匹配到每个CommonUnit下:
$masterCommonUnit = CommonUnit::select('id_common_unit', 'name_unit', 'information_unit', 'created_by', 'edited_by') ->with(['items' => function ($query) { $query->select('id_item', 'item_id_common_unit'); }]) ->orderBy($order, $dir) ->get() ->toArray();
返回的结果里每个CommonUnit条目下都会有items字段,存储所有关联的Item子记录,天然按父表id分组。
方案B:SQL层面左连接分组查询
如果确实需要在SQL层面执行左连接连表后分组,直接用leftJoin方法:
$masterCommonUnit = CommonUnit::select( 'common_units.id_common_unit', 'common_units.name_unit', 'common_units.information_unit', 'common_units.created_by', 'common_units.edited_by', // 按需聚合Item字段,比如统计每个CommonUnit关联的Item数量 \DB::raw('COUNT(items.id_item) as item_count'), \DB::raw('GROUP_CONCAT(items.id_item) as item_ids') ) ->leftJoin('items', 'common_units.id_common_unit', '=', 'items.item_id_common_unit') ->orderBy($order, $dir) ->groupBy('common_units.id_common_unit') ->get() ->toArray();
注意:如果开启了MySQL的
ONLY_FULL_GROUP_BY模式,select里所有非聚合的字段都必须出现在groupBy里,上述写法默认id_common_unit是common_units的主键,所以可以只按这个字段分组。
内容的提问来源于stack exchange,提问作者ProLuck
相关产品推荐
相关产品推荐

