You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel统计clients表指定年份各月记录数 解决非首月计数为0问题

问题原因

Laravel查询构造器为可变对象,你初始化的$clientYear是同一个查询实例,每次调用whereMonth都会在原有查询条件上叠加。执行完第一个月的查询后,查询条件已经变为whereYear('created_at', $selectedYear) and whereMonth('created_at', 1),后续再叠加其他月份的条件,就变成同时要求月份等于1和2等不可能满足的逻辑,自然返回计数为0。


调整方案

提供两种可选方案,第一种为最小改动修复原有逻辑,第二种为性能更优的推荐方案。

方案1:克隆查询实例避免条件叠加(最小改动)

每次计数前克隆基础查询实例,保证每次查询的条件独立,不会互相叠加:

public function clientsCount(Request $request)
{
    $selectedYear = $request->selectedYear ?? now()->format('Y');

    $orderedMonthsData = [
        1 => "January ". $selectedYear,
        2 => "February ". $selectedYear,
        3 => "March ". $selectedYear,
        4 => "April ". $selectedYear,
        5 => "May ". $selectedYear,
        6 => "June ". $selectedYear,
        7 => "July ". $selectedYear,
        8 => "August ". $selectedYear,
        9 => "September ". $selectedYear,
        10 => "October ". $selectedYear,
        11 => "November ". $selectedYear,
        12 => "December ". $selectedYear
    ];

    $clientYearBaseQuery = Client::query()->whereYear('created_at', $selectedYear);

    $orderedClientsData = [
        1 => (clone $clientYearBaseQuery)->whereMonth('created_at', 1)->count(),
        2 => (clone $clientYearBaseQuery)->whereMonth('created_at', 2)->count(),
        3 => (clone $clientYearBaseQuery)->whereMonth('created_at', 3)->count(),
        4 => (clone $clientYearBaseQuery)->whereMonth('created_at', 4)->count(),
        5 => (clone $clientYearBaseQuery)->whereMonth('created_at', 5)->count(),
        6 => (clone $clientYearBaseQuery)->whereMonth('created_at', 6)->count(),
        7 => (clone $clientYearBaseQuery)->whereMonth('created_at', 7)->count(),
        8 => (clone $clientYearBaseQuery)->whereMonth('created_at', 8)->count(),
        9 => (clone $clientYearBaseQuery)->whereMonth('created_at', 9)->count(),
        10 => (clone $clientYearBaseQuery)->whereMonth('created_at', 10)->count(),
        11 => (clone $clientYearBaseQuery)->whereMonth('created_at', 11)->count(),
        12 => (clone $clientYearBaseQuery)->whereMonth('created_at', 12)->count(),
    ];

    dd($orderedMonthsData, $orderedClientsData);
}

方案2:一次性分组统计(性能更优,推荐)

方案1会执行12次数据库查询,数据量大时性能较差。你可以用分组统计一次性拿到所有月份的计数,再补全没有数据的月份即可:

public function clientsCount(Request $request)
{
    $selectedYear = $request->selectedYear ?? now()->format('Y');

    // 初始化月份标签和默认计数为0的数组
    $orderedMonthsData = [];
    $orderedClientsData = array_fill(1, 12, 0);
    for ($i = 1; $i <= 12; $i++) {
        $monthName = date('F', mktime(0, 0, 0, $i, 1));
        $orderedMonthsData[$i] = "{$monthName} {$selectedYear}";
    }

    // 一次性统计所有有数据的月份的记录数
    $monthlyCounts = Client::query()
        ->whereYear('created_at', $selectedYear)
        ->selectRaw('MONTH(created_at) as month, count(*) as count')
        ->groupBy('month')
        ->pluck('count', 'month');

    // 把查询结果填充到计数数组中
    foreach ($monthlyCounts as $month => $count) {
        $orderedClientsData[$month] = $count;
    }

    dd($orderedMonthsData, $orderedClientsData);
}

内容的提问来源于stack exchange,提问作者Bold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 16:45:03