在 laravel 10 中应使用 selectraw('date(created_at) as date') 配合 groupby(db::raw('date(created_at)')) 实现跨数据库兼容的每日分组统计,避免仅依赖别名分组或内存处理。

在 Laravel 10 中,若需按「每日」对数据进行分组统计(例如统计每天的订单数、访问量等),不能直接用原生 SQL 的 DATE() 函数写死在查询里,而应借助 Laravel 的查询构建器提供的日期处理能力,结合数据库方言(如 MySQL)安全、高效地实现。
使用 selectRaw + DATE() 进行分组
这是最常用且兼容性较好的方式,适用于 MySQL。Laravel 允许你在 selectRaw 中使用原生函数,并在 groupBy 中复用该表达式:
$dailyStats = DB::table('orders')
->selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->whereBetween('created_at', ['2024-01-01', '2024-01-31'])
->groupBy('date')
->orderBy('date')
->get();
注意:groupBy('date') 中的 date 是别名,MySQL 支持按 SELECT 中的别名分组;但 PostgreSQL 或 SQLite 需改用表达式(见下文)。
适配多数据库:用 DB::raw 统一写法
为避免不同数据库对别名分组的支持差异,推荐显式写出分组表达式:
$dailyStats = DB::table('orders')
->selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->whereBetween('created_at', ['2024-01-01', '2024-01-31'])
->groupBy(DB::raw('DATE(created_at)'))
->orderBy('date')
->get();
这样无论 MySQL、PostgreSQL(用 DATE(created_at))还是 SQLite(用 DATE(created_at))都能正常工作(PostgreSQL 实际常用 created_at::date,但 Laravel 的 DATE() 在较新版本中已做兼容封装)。
使用 Eloquent 模型 + toDateString()(仅限内存后处理,不推荐大数据量)
如果你已有模型集合(比如小范围数据),可用集合方法分组:
$orders = Order::whereBetween('created_at', ['2024-01-01', '2024-01-31'])->get();
$dailyStats = $orders->groupBy(function ($order) {
return $order->created_at->toDateString(); // 转为 'Y-m-d' 字符串
})->mapWithKeys(function ($group, $date) {
return [$date => $group->count()];
});
⚠️ 注意:这种方式会把全部数据查到 PHP 内存再分组,**不适合万级以上的数据**,仅作演示或调试用。
补充:其他常见日期粒度写法
同理可扩展为按周、月、年统计:
- 按周:→
selectRaw('YEARWEEK(created_at, 1) as week')+groupBy('week') - 按月:→
selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month')(MySQL) - 按年:→
selectRaw('YEAR(created_at) as year')
使用时注意时区——确保数据库和 Laravel 的 app.timezone 一致,否则 DATE(created_at) 可能跨天。











