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

能否简化查询适配paginate?无需自定义分页器且兼容Query Builder

问题:Laravel中如何用Query Builder/Eloquent实现每个用户最早消息的分页查询?

我有一组用户消息数据,需要获取每个用户发布的最早消息,之后对结果使用paginate()方法。示例数据如下:

id | user_id |     message    | date_posted
1  |    5    |  some_message  |  2022-07-15  
2  |   125   |  some_message  |  2022-08-02  
3  |    5    |  some_message  |  2022-04-05 

需求是仅获取ID为2和3的数据行。当前用DB::select(DB::raw($query))执行的查询返回数组,无法使用paginate()方法,现有SQL语句为:

select T.*
from (select *,
             row_number() over (partition by user_id order by date_posted, id) as sn
      from my_table
     ) T
where sn = 1;

请问能否将其转换为Query Builder或Eloquent语句实现?注:无法关闭only_full_group_by配置。


解决方案

1. Query Builder 实现方式

利用Laravel的fromSub()方法构建子查询,完全匹配原生SQL逻辑,同时支持分页:

// 构建子查询:给每个用户的消息按发布时间+ID排序并编号
$subquery = DB::table('my_table')
    ->selectRaw('*, row_number() over (partition by user_id order by date_posted, id) as sn');

// 主查询:筛选编号为1的记录(即每个用户的最早消息)并分页
$paginatedResults = DB::table($subquery, 'T')
    ->where('sn', 1)
    ->paginate(15); // 替换为你需要的每页条数

2. Eloquent 模型实现方式

如果有对应的消息模型(比如App\Models\Message),写法类似:

use App\Models\Message;

$subquery = Message::selectRaw('*, row_number() over (partition by user_id order by date_posted, id) as sn');

$paginatedResults = Message::fromSub($subquery, 'T')
    ->where('sn', 1)
    ->paginate(15);

关键说明

  • fromSub()方法支持将子查询作为主查询的数据源,既保留了窗口函数的筛选逻辑,又能返回支持paginate()的查询构建器实例。
  • 这种写法完全兼容only_full_group_by配置,因为没有使用不符合分组规则的聚合操作,而是通过窗口函数精准筛选每个用户的第一条消息。

内容的提问来源于stack exchange,提问作者pileup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:30:53