Laravel 5.8 Query Builder分组失效求助:如何按table_name分组
解决Laravel Query Builder分组未生效的问题
看起来你遇到的问题是同时按两个字段分组导致结果不符合预期——你当前的groupBy('c.key', 'c.table_name')会把key和table_name的组合作为分组依据,只有当这两个字段完全匹配的行才会被归为一组,这就导致即使table_name相同,只要key不同,就会生成独立的分组。
下面分两种场景给出解决方案:
场景1:仅按table_name分组,聚合关联的key
如果你的需求是每个table_name只出现一次,同时需要获取该分组下的所有key,可以用MySQL的聚合函数(比如GROUP_CONCAT)来合并key,并只按table_name分组:
$data['list_module'] = DB::table('roles as a') ->leftJoin('permission_role as b', 'a.id', 'b.role_id') ->leftJoin('permissions as c', 'b.permission_id', 'c.id') ->where('a.id', $id) // 选择table_name,并用GROUP_CONCAT聚合同一分组下的所有唯一key ->select('c.table_name', DB::raw('GROUP_CONCAT(DISTINCT c.key) as permission_keys')) // 仅按table_name分组 ->groupBy('c.table_name') ->orderBy('c.table_name', 'DESC') ->get();
这段代码会返回每个table_name对应的一行数据,permission_keys字段是该分组下所有key用逗号分隔的字符串。如果需要把permission_keys转为数组,可以在获取结果后处理:
$data['list_module'] = $data['list_module']->map(function ($item) { $item->permission_keys = explode(',', $item->permission_keys); return $item; });
场景2:保留所有key,但在结果集中按table_name分组展示
如果你的需求是保留所有key数据,只是在逻辑上按table_name分组,可以先获取全部数据,再用Laravel集合的groupBy方法处理:
// 先获取所有原始数据 $rawPermissions = DB::table('roles as a') ->leftJoin('permission_role as b', 'a.id', 'b.role_id') ->leftJoin('permissions as c', 'b.permission_id', 'c.id') ->where('a.id', $id) ->select('c.key','c.table_name') ->orderBy('c.table_name', 'DESC') ->get(); // 用集合的groupBy方法按table_name分组 $data['list_module'] = $rawPermissions->groupBy('table_name');
最终$data['list_module']会是一个集合,键为table_name的值,对应的值是该分组下所有包含key和table_name的对象数组。
额外提醒:MySQL严格模式注意事项
如果你的Laravel项目开启了MySQL严格模式(默认是开启的),groupBy必须遵循ONLY_FULL_GROUP_BY规则:select中的字段要么出现在groupBy里,要么是被聚合函数处理过的字段。上面的两种方案都符合这个规则,不会触发报错。
内容的提问来源于stack exchange,提问作者Rahmat Effendi
相关产品推荐
相关产品推荐

