laravel 11 查询近30天每日数据需用eloquent日期范围+分组统计+carbon处理,核心步骤包括:1. 基础查询按日分组并补全缺失日期;2. 用cte优化生成连续日期;3. 封装作用域复用;4. 注意时区、索引、空数据和软删除。

<p>要查询 Laravel 11 中近 30 天的每日数据(如订单数、用户注册数等),核心是用 Eloquent 的日期范围 + 分组统计,配合 Carbon 处理时间。以下是一个完整、可直接运行的示例,以 <strong>用户注册数</strong> 为例:</p>
<h3>1. 基础模型查询(按日分组统计)</h3>
<p>假设你有 <code>User</code> 模型,<code>created_at</code> 是注册时间字段:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7885" title="laravel-specialist"><img
src="https://img.php.cn/upload/skill/000/000/081/179172020840450.jpg" alt="laravel-specialist" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7885" title="laravel-specialist" class="overflowclass">laravel-specialist</a>
<p class="overflowclass">精通 Laravel 10+,遵循现代 PHP 实践的 Laravel 专家。擅长优雅语法、Eloquent ORM、队列系统及企业级特性...</p>
</div>
<a rel="nofollow" href="/xiazai/skill7885" title="laravel-specialist" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<font color="#666">
<pre class="brush:php;toolbar:false;"><code>// app/Http/Controllers/ReportController.php
use App\Models\User;
use Carbon\Carbon;
public function dailyRegistrations()
{
$thirtyDaysAgo = now()->subDays(29); // 从今天起往前推 29 天,共 30 天(含今天)
$data = User::whereBetween('created_at', [$thirtyDaysAgo, now()])
->selectRaw('DATE(created_at) as date')
->selectRaw('COUNT(*) as count')
->groupBy('date')
->orderBy('date')
->get();
// 补全缺失日期(如某天无注册,返回 0)
$fullRange = collect();
for ($i = 29; $i >= 0; $i--) {
$date = now()->subDays($i)->format('Y-m-d');
$item = $data->firstWhere('date', $date);
$fullRange->push([
'date' => $date,
'count' => $item ? (int)$item->count : 0,
]);
}
return response()->json($fullRange);
}</code>
2. 使用数据库原生函数优化(推荐 MySQL/PostgreSQL)
避免 PHP 循环补全,改用 SQL 生成连续日期(MySQL 8.0+ 或 PostgreSQL):
<code>// 仅适用于支持 CTE 的数据库(如 MySQL 8.0+)
$rawSql = "
WITH RECURSIVE dates AS (
SELECT ? AS date
UNION ALL
SELECT DATE_ADD(date, INTERVAL 1 DAY)
FROM dates
WHERE date = ?
GROUP BY DATE(created_at)
) u ON d.date = u.date
ORDER BY d.date
";
$thirtyDaysAgo = now()->subDays(29)->format('Y-m-d');
$today = now()->format('Y-m-d');
$data = DB::select($rawSql, [$thirtyDaysAgo, $today, $thirtyDaysAgo]);
return response()->json($data);</code>
3. 封装成复用的查询构建器方法
在模型或 Repository 中封装,便于多处调用:
<code>// 在 User.php 模型中添加作用域
public function scopeForLast30Days($query)
{
return $query->whereBetween('created_at', [
now()->subDays(29),
now()
]);
}
// 调用时
$data = User::forLast30Days()
->selectRaw('DATE(created_at) as date, COUNT(*) as count')
->groupBy('date')
->orderBy('date')
->get()
->mapWithKeys(function ($item) {
return [$item->date => (int)$item->count];
})
->pipe(function ($map) {
$result = [];
for ($i = 29; $i >= 0; $i--) {
$date = now()->subDays($i)->format('Y-m-d');
$result[] = [
'date' => $date,
'count' => $map->get($date, 0)
];
}
return $result;
});</code>
4. 注意事项与常见问题
-
时区一致性:确保 PHP、MySQL 和应用配置(
config/app.php中'timezone' => 'Asia/Shanghai')一致,否则日期可能偏移 -
索引优化:为
created_at字段添加索引:$table->index('created_at'); - 空数据处理:Eloquent 默认不返回 0 值日期,必须手动补全(如示例中用循环或 CTE)
-
软删除模型:若使用
SoftDeletes,需加withTrashed()或明确whereNull('deleted_at')










