Laravel 11中统计每日数据需用DB::raw("DATE(created_at) as date")在select中生成日期字段,再groupBy('date'),并确保SELECT仅含分组字段和聚合字段;禁用strict模式虽可绕过报错但不推荐,因会引发结果不可靠与环境不兼容问题。

在 Laravel 11 中统计每日数据(如按 created_at 分组计数),直接用 groupBy('date') 很容易触发 MySQL 严格模式报错:Expression #1 of SELECT list is not in GROUP BY clause。这不是 Laravel 的 bug,而是 MySQL 5.7+ 默认启用 ONLY_FULL_GROUP_BY 后的合规校验——核心原则是:**SELECT 中所有非聚合字段,必须显式出现在 GROUP BY 中**。
用 DATE() 提取日期并显式分组
避免依赖模糊字段,把时间转为标准日期再分组:
- 用
DB::raw("DATE(created_at) as date")在select()中生成日期字段 -
groupBy('date')必须和 select 中的别名完全一致(不能写groupBy(DB::raw('DATE(created_at)'))) - 确保其他非聚合字段不出现在 select 列表里,只保留分组字段 + 聚合字段
示例:
DB::table('orders')
->select(DB::raw("DATE(created_at) as date"), DB::raw('COUNT(*) as count'))
->whereDate('created_at', '>=', now()->subWeek())
->groupBy('date')
->orderBy('date')
->get();
用 selectRaw 统一管理字段与分组逻辑
更清晰、不易出错的方式是全部收口到 selectRaw:
- 所有字段(包括日期提取、聚合函数)都写进
selectRaw()字符串中 -
groupBy()直接传入别名(如'date'),或重复写表达式(如DB::raw('DATE(created_at)')) - 推荐用别名方式,语义明确且适配大多数 MySQL 版本
示例:
DB::table('logs')
->selectRaw("DATE(created_at) as date, COUNT(*) as total, SUM(duration) as sum_duration")
->whereBetween('created_at', [now()->startOfDay(), now()])
->groupBy('date')
->get();
需要过滤分组结果?加上 havingRaw
如果只要「日订单数 ≥ 5」的数据,不能用 where(),必须用 havingRaw():
-
havingRaw()是对分组后的结果做条件筛选,对应 SQL 的HAVING - 参数务必用占位符绑定(
?+ 数组),防 SQL 注入 - 别名字段(如
count)可在havingRaw中直接使用
示例:
DB::table('orders')
->selectRaw("DATE(created_at) as date, COUNT(*) as count")
->whereYear('created_at', 2026)
->groupBy('date')
->havingRaw('COUNT(*) >= ?', [5])
->orderByDesc('count')
->get();
不建议关 strict 模式
虽然把 config/database.php 中 'strict' => true 改成 false 能绕过报错,但不推荐:
- 掩盖语义问题:同一日期下若有多条记录,
SELECT *会随机返回某一行的非分组字段(如name),结果不可靠 - 降低可移植性:换到严格模式环境(如生产数据库、Docker 镜像)立刻报错
- Laravel 11 更强调显式契约,主动适配比被动降级更可持续


















