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

Laravel多数据库统计导出CSV异常排查及优化建议

问题描述

我编写了一个Laravel命令脚本,用于遍历多个数据库统计对象数量,匹配「名称-对象数量」并导出为CSV文件。核心代码如下:

$formatted_data = array();
$providers = provider::where('del', 'no')->get();       
foreach($providers as $provider){   
    $formatted_data[$provider['id']]['name'] = $provider['name'];
}

$objectMappingsModels = array((new objectMapping1), (new objectMapping2),
 (new objectMapping3), (new objectMapping4), (new objectMapping5),
 (new objectMapping6), (new objectMapping7), (new objectMapping8));

foreach($objectMappingsModels as $objectMappingsModel){
    $totals = $objectMappingsModel::select('providerFK', DB::raw('count(*) as total'), 
                                                         DB::raw('monthName(ut) as month_name')
                                          )
                                  ->where('userFK', '!=', 1)  
                                  ->where('del', 'no')
                                  ->whereMonth('ut', $this->option('month'))   
                                  ->whereYear('ut', $this->option('year'))
                                  ->groupBy('providerFK', 'month_name')
                                  ->get()
                                  ->toArray();              

    foreach($totals as $total){
        $formatted_data[$total['providerFK']]['count'] = $total['total'];
    }   

}
$responce =  Excel::store(new UsersExport($formatted_data), 'testNameDate.csv',null, \Maatwebsite\Excel\Excel::CSV);
return true;

导出类代码:

class UsersExport implements FromArray
{
    protected $invoices;

    public function __construct(array $invoices)
    {
        $this->invoices = $invoices;
    }

    public function array(): array
    {
        return $this->invoices;
    }
}

目前脚本运行存在异常:统计结果偶尔不准确,且导出的CSV最后一行总是只有随机数字(无关联名称)。

问题原因分析

1. 统计结果不准确

  • 多模型遍历统计时,后一个模型的统计结果会直接覆盖前一个模型同providerFK的count值,最终仅保留最后一个模型的统计数据,导致总统计量缺失。
  • 未初始化count字段,无数据的服务商对应的count会缺失,导出CSV时易出现数据错位或统计遗漏。

2. CSV最后一行出现随机数字

  • $formatted_data是关联数组,键为服务商ID,Maatwebsite Excel导出时会将数组键额外输出到CSV中,所谓的"随机数字"实际是某个服务商的ID,因关联数组的导出逻辑导致键被错误展示。
  • 数组中存在未正确初始化的空元素/键值对,引发导出时的异常行。
代码优化方案

1. 修复统计逻辑,累加多模型数据

将count的覆盖逻辑改为累加,同时初始化每个服务商的count为0,确保无数据时显示0:

$formatted_data = [];
$providers = provider::where('del', 'no')->get();       
foreach($providers as $provider){   
    // 初始化name和count字段,count默认0
    $formatted_data[$provider['id']] = [
        'name' => $provider['name'],
        'count' => 0
    ];
}

$objectMappingsModels = [
    new objectMapping1,
    new objectMapping2,
    new objectMapping3,
    new objectMapping4,
    new objectMapping5,
    new objectMapping6,
    new objectMapping7,
    new objectMapping8
];

foreach($objectMappingsModels as $objectMappingsModel){
    $totals = $objectMappingsModel::select('providerFK', DB::raw('count(*) as total'))
                                  ->where('userFK', '!=', 1)  
                                  ->where('del', 'no')
                                  ->whereMonth('ut', $this->option('month'))   
                                  ->whereYear('ut', $this->option('year'))
                                  ->groupBy('providerFK')
                                  ->get()
                                  ->toArray();              

    foreach($totals as $total){
        // 累加每个模型的统计量,而非覆盖
        if(isset($formatted_data[$total['providerFK']])){
            $formatted_data[$total['providerFK']]['count'] += $total['total'];
        }
    }   
}

2. 修复CSV导出异常问题

修改导出类,将关联数组转为索引数组,同时添加表头,避免键被输出:

use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromArray, WithHeadings
{
    protected $data;

    public function __construct(array $data)
    {
        // 将关联数组转为索引数组,只保留值部分
        $this->data = array_values($data);
    }

    public function array(): array
    {
        return $this->data;
    }

    // 添加CSV表头
    public function headings(): array
    {
        return ['服务商名称', '对象数量'];
    }
}

3. 其他优化点

  • 使用短数组语法[]替代array(),符合现代PHP规范。
  • 移除不必要的month_name查询,已通过whereMonth和whereYear限定时间,无需再按月份名称分组。
  • 增加isset判断,避免不存在的providerFK导致数组下标错误。
  • 导出时添加时间戳到文件名,避免文件覆盖:
$fileName = 'provider_stats_' . date('YmdHis') . '.csv';
$response = Excel::store(new UsersExport($formatted_data), $fileName, null, \Maatwebsite\Excel\Excel::CSV);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:15:34