laravel 10中需用selectraw+groupby实现按日分组统计,并手动分页:先selectraw('date(created_at) as date')和count(*),再collect后forpage切片,最后用lengthawarepaginator封装。

在 Laravel 10 中实现按日分组的分页统计,关键在于:数据库聚合 + 分页适配 + 时间字段正确处理。直接用 groupBy('date') 后调用 paginate() 会报错,因为 MySQL 严格模式下非聚合字段不能出现在 SELECT 中。必须用 DATE() 函数提取日期并配合 selectRaw 显式声明聚合字段。
使用 selectRaw + groupBy 实现每日分组
假设统计订单表 orders 每日创建数量:
- 用
selectRaw('DATE(created_at) as date')提取日期(不带时分秒) - 用
selectRaw('COUNT(*) as count')做聚合统计 - 必须把所有 SELECT 字段都写进
GROUP BY,即groupBy('date') - 注意:不能混用
select('*')和groupBy,否则查询会失败
手动分页避免 paginate() 报错
Laravel 的 paginate() 内部会自动加 COUNT(*) 查询总数,但 GROUP BY 场景下这个 COUNT 不符合预期。推荐用 forPage() 手动分页:
- 先查出全部分组结果(或加 LIMIT 优化),用
collect()转集合 - 用
forPage($page, $perPage)切片数据 - 用
count()获取总条数(注意:这是分组后天数总数,不是原始记录数) - 最后用
LengthAwarePaginator包装,传入切片数据、总数、当前页、每页数
完整示例代码(含 Paginator 构造)
控制器中:
$perPage = 15;
$page = request('page', 1);
// 查询每日统计(不带分页)
$rawData = Order::selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->whereBetween('created_at', [now()->subDays(30), now()])
->groupBy('date')
->orderBy('date', 'desc')
->get();
// 转集合并分页
$collection = collect($rawData);
$total = $collection->count();
$items = $collection->forPage($page, $perPage);
// 构造分页器
$paginator = new \Illuminate\Pagination\LengthAwarePaginator(
$items,
$total,
$perPage,
$page,
['path' => request()->url(), 'query' => request()->query()]
);
return view('stats.daily', compact('paginator'));
补充说明
如果数据量极大(比如百万级订单),建议给 created_at 字段加索引;也可考虑用数据库视图或物化临时表预计算;Laravel 10 不支持原生 GROUP BY 分页,所以不要尝试在 paginate() 前加 groupBy —— 它会直接抛异常。











