在 Laravel 12 中,按 created_at 字段分组获取每日数据应使用 selectRaw('DATE(created_at) as date') + groupBy('date') 实现跨数据库兼容;也可用 castDate() 配合访问器增强语义,但 groupBy 仍需原始 SQL 截断。

在 Laravel 12 中,按 created_at 字段分组获取每日数据,核心是把时间字段「截断」到天级别(即去掉时分秒),再用 groupBy 聚合。不同数据库语法略有差异,Laravel 提供了跨库兼容的写法,推荐优先使用 date() 或 castDate() 辅助方法。
使用 selectRaw + groupBy(通用方案)
适用于 MySQL、PostgreSQL、SQLite,Laravel 会自动适配底层函数:
- MySQL:用
DATE(created_at) - PostgreSQL:用
created_at::date或DATE(created_at) - SQLite:用
DATE(created_at)
示例代码(获取每日创建的文章数):
$dailyStats = Post::selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->groupBy('date')
->orderBy('date', 'desc')
->get();
返回结果中 date 是字符串格式(如 "2024-06-15"),可直接用于图表或列表展示。
使用 whereDate 配合循环(适合小范围日期)
如果只需某几天的数据,或需对每日做复杂处理(如关联查询、计算衍生字段),可先获取日期范围,再逐日查:
$start = now()->subDays(6); // 近7天
$end = now();
$dates = collect(\Carbon\CarbonPeriod::create($start, $end))
->map(fn($date) => $date->format('Y-m-d'));
$dailyData = $dates->mapWithKeys(function ($date) {
return [$date => Post::whereDate('created_at', $date)->count()];
});
注意:此方式 N+1 查询风险高,仅建议数据量小或需定制逻辑时使用。
使用 castDate() 和模型访问器(语义化增强)
在模型中定义一个只读访问器,让每日分组更清晰:
// 在 Post.php 模型中
protected $casts = [
'created_at' => 'datetime',
];
public function getCreatedAtDateAttribute()
{
return $this->created_at->format('Y-m-d');
}
然后在查询中使用(注意:不能直接在 groupBy 中用访问器,仍需 selectRaw):
$dailyStats = Post::selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->groupBy('date')
->get()
->map(fn($item) => $item->merge(['date_formatted' => \Carbon\Carbon::parse($item->date)->isoFormat('MMM D')])); // 如 Jun 15
补充:带时区注意事项
若应用设置了非 UTC 时区(如 'Asia/Shanghai'),确保数据库连接也同步时区,否则 DATE(created_at) 可能按服务器本地时间截取。可在数据库配置中加:
// config/database.php → mysql connections
'options' => [
\PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone = '+08:00'"
]
或统一用 UTC 存储时间,查询时再转换显示,避免歧义。


















