You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 19:20:35