laravel 12中按天汇总数据需用date(created_at)分组并确保select字段与group by严格对齐,推荐写法:select(db::raw('date(created_at) as day'), db::raw('sum(total_amount) as total'))->groupby('day')。

在 Laravel 12 中用查询构造器按天汇总数据,核心是结合 groupBy() 与日期格式化函数(如 DATE() 或 DATE_FORMAT()),再配合 sum()、count() 等聚合函数。关键在于让分组字段和 SELECT 中的日期字段严格对齐,否则在严格 SQL 模式下会报错。
用 DATE() 函数按天分组最简洁
MySQL 的 DATE(created_at) 可直接提取年月日部分,适合多数场景:
-
推荐写法(安全、可读、兼容性好):
DB::table('orders')<br> ->select(DB::raw('DATE(created_at) as day'), DB::raw('SUM(total_amount) as total'))<br> ->whereBetween('created_at', ['2026-10-01', '2026-10-15'])<br> ->groupBy('day')<br> ->get(); - 注意:
groupBy('day')中的day是别名,Laravel 会自动映射到DATE(created_at);但若用groupBy(DB::raw('DATE(created_at)'))更显式,也更稳妥 - 结果中
day是字符串格式,如"2026-10-05",可直接用于前端图表横轴
避免 GROUP BY 报错的两个要点
Laravel 12 默认启用 MySQL 的 ONLY_FULL_GROUP_BY 模式,以下写法会失败:
- ❌ 错误示例:
->select('id', DB::raw('SUM(price)'))->groupBy('DATE(created_at)')——id既没聚合也没分组 - ✅ 正确做法:SELECT 中只出现分组字段或聚合字段
->select(DB::raw('DATE(created_at) as date'), DB::raw('COUNT(*) as cnt'), DB::raw('AVG(price) as avg_price'))<br> ->groupBy('date') - 如果需要关联其他表(如用户姓名),不能直接
select('users.name'),应改用join+ 分组对齐,或改用 Eloquent 的withCount()/ 预加载
补充:按自然日(今天/昨天/本周)快速筛选
借助 Carbon 可写出语义清晰的时间条件:
- 统计「今天」订单总额:
->whereDate('created_at', today())<br> ->sum('total_amount') - 统计「最近7天」每日笔数:
->where('created_at', '>=', now()->subDays(6)->startOfDay())<br> ->groupBy(DB::raw('DATE(created_at)'))<br> ->select(DB::raw('DATE(created_at) as day'), DB::raw('COUNT(*) as count'))<br> ->get() - 注意:
whereDate()底层调用DATE(),性能良好;但不要在WHERE中对时间字段用FROM_UNIXTIME()或YEAR/MONTH(),会导致索引失效
小技巧:补全无数据的日期(前端或后端均可)
原生查询不会返回“某天无记录”的空行,常见处理方式:
- 前端补:拿到最小/最大日期后,用 JS 生成连续日期数组,再 merge 数据
- 后端补(少量日期):查出有数据的日期后,用 PHP 循环填充缺失项,例如:
$dates = collect(range(0, 6))->map(fn($i) => today()->subDays($i)->format('Y-m-d'))->flip();<br>$result = $query->keyBy('day')->merge($dates->map(fn() => ['day' => null, 'total' => 0])); - 数据库补(较重):用 UNION ALL 拼接日期序列(需 MySQL 8.0+ CTE 或临时表),一般不推荐











