如何用Eloquent查询获取每个分组的前5条记录?
问题分析与解决
错误原因
WhereRaw参数用法错误:
第一次调用WhereRaw(['n','<=','5'])时,WhereRaw不接受数组作为参数,它要求传入完整的SQL条件字符串,因此触发了“Array to string conversion”错误。
第二次改为WhereRaw('n','<=','5')依然错误——WhereRaw的正确用法是第一个参数为SQL条件片段,后续参数为绑定值(如WhereRaw('n <= ?', [5])),你传入三个独立参数会导致Laravel生成语法错误的SQL语句。窗口函数别名不能直接在WHERE中使用:
MySQL的执行顺序是先处理FROM/JOIN,再执行WHERE过滤,最后才计算窗口函数。因此直接在WHERE中引用窗口函数生成的n别名,SQL本身不支持,这是核心语法错误的根源,必须通过子查询或CTE先计算出n,再在外层进行过滤。
正确的Eloquent实现
方式1:子查询实现
$trees = Tree::from( Tree::select(['*', DB::raw('ROW_NUMBER() OVER (PARTITION BY secid ORDER BY created_at DESC) AS n')]) ->as('x') ) ->where('n', '<=', 5) ->get();
方式2:CTE实现(Laravel 8及以上版本支持)
$trees = Tree::withExpression('x', function ($query) { $query->select(['*', DB::raw('ROW_NUMBER() OVER (PARTITION BY secid ORDER BY created_at DESC) AS n')]) ->from('trees'); }) ->from('x') ->where('n', '<=', 5) ->get();
代码说明
- 两种方式都完全复刻了你原始MySQL语句的逻辑:先在内部查询中为每个
secid分组计算行号n,再在外层筛选出行号≤5的记录。 - 使用
as('x')为子查询设置别名,对应原始SQL中的AS x。 - 通过嵌套查询避开了MySQL窗口函数执行顺序的限制,确保
n能被正确引用过滤。
内容的提问来源于stack exchange,提问作者Ruwan Liyanage
相关产品推荐
相关产品推荐

