在 laravel 12 中应使用 db::table() 配合 selectraw、groupbyraw 和 orderbyraw 按天聚合数据,如 selectraw('date(created_at) as day, count(*) as count') + groupbyraw('date(created_at)') + orderbyraw('date(created_at) desc'),并加 wheredate 限制范围、注意反斜杠转义与时区一致性。

在 Laravel 12 中,使用 DB::table() 按天聚合数据,核心是借助数据库的日期函数(如 DATE())进行分组,并用 Query Builder 的原生表达式确保 SQL 正确生成。Eloquent 不适合这类聚合场景,应直接使用查询构建器。
正确写法:用 selectRaw + groupByRaw 按天分组
假设你有一张 views 表,想统计每天的访问数量:
- 使用
selectRaw('DATE(created_at) as day, COUNT(*) as count')提取日期并计数 - 必须用
groupByRaw('DATE(created_at)'),不能只写groupBy('created_at'),否则会按完整时间戳(含时分秒)分组,导致同一天多条记录被拆开 - 加
orderByRaw('DATE(created_at) DESC')确保按日期倒序排列,避免排序不稳定 - 推荐加上时间范围限制,比如
whereDate('created_at', '>=', now()->subMonth()),提升性能和结果可控性
完整可运行示例
控制器中:
use IlluminateSupportFacadesDB;
$stats = DB::table('views')
->selectRaw('DATE(created_at) as day, COUNT(*) as count')
->where('view_type', 'App\Title') // 注意双反斜杠转义
->whereDate('created_at', '>=', now()->sub30Days())
->groupByRaw('DATE(created_at)')
->orderByRaw('DATE(created_at) DESC')
->get();
返回结果是标准对象集合,每项形如:{ "day": "2026-10-20", "count": 42 }。
注意事项与常见坑
-
反斜杠转义:字符串值中含命名空间(如
'AppTitle'),PHP 会把T当作制表符,务必写成'App\Title' -
不要在 PHP 层分页:聚合后需限制条数时,用
limit(30)让数据库执行,而非->get()->take(30) -
索引优化:确保
created_at字段有索引;若频繁按日查,可考虑添加函数索引(MySQL 8.0+):CREATE INDEX idx_created_date ON views ((DATE(created_at))); - 时区一致性:确认应用时区与数据库时区一致,或统一用 UTC 存储,避免因时区转换导致某天数据错位
扩展:支持跨月/年聚合的写法
如需按年月汇总(如 2026-10),可改用:
->selectRaw("DATE_FORMAT(created_at, '%Y-%m') as month, COUNT(*) as count")
->groupByRaw("DATE_FORMAT(created_at, '%Y-%m')")
注意:DATE_FORMAT 是 MySQL 函数,PostgreSQL 应用 TO_CHAR(created_at, 'YYYY-MM') 并配合 selectRaw 和 groupByRaw 替换。











