Laravel使用join关联查询时groupBy导致orderBy排序失效问题
问题根因
- 你原写法的排序逻辑执行在
group by分组操作之前,分组操作会直接打乱预排序的结果,且分组后你没有指定取该房间下哪一条聊天记录的created_at作为排序依据,数据库会随机取该分组内的某条记录的时间排序,自然不符合预期。 - 不加
group by时所有聊天记录都保留,排序是按所有聊天的时间倒序,逻辑是对的,但会出现房间重复的问题。
解决方案
直接用聚合函数MAX()取每个房间对应的最新聊天时间作为排序依据即可,修改后的代码如下:
$items = $items->select("rooms.*") ->join("chats", "chats.room_id", "=", "rooms.id") ->groupBy('rooms.id') ->orderByRaw("MAX(chats.created_at) DESC");
扩展适配(可选)
如果需要保留没有任何聊天记录的房间,将join替换为leftJoin即可,同时适配无聊天记录的房间排序规则(默认排到最后):
// PostgreSQL写法 $items = $items->select("rooms.*") ->leftJoin("chats", "chats.room_id", "=", "rooms.id") ->groupBy('rooms.id') ->orderByRaw("MAX(chats.created_at) DESC NULLS LAST"); // MySQL写法(不支持NULLS LAST语法) $items = $items->select("rooms.*") ->leftJoin("chats", "chats.room_id", "=", "rooms.id") ->groupBy('rooms.id') ->orderByRaw("IFNULL(MAX(chats.created_at), '1970-01-01') DESC");
注意事项
如果你的数据库开启了严格模式,只要rooms.id是rooms表的主键,上面仅选择rooms.*的写法在MySQL 5.7+、PostgreSQL等主流数据库中都符合group by的语法规范,不会报错。
内容的提问来源于stack exchange,提问作者Jaeger
相关产品推荐
相关产品推荐

