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

如何在laravel-excel中分别统计更新与插入的行数

Laravel Excel WithUpserts 场景下分别统计插入、更新行数实现方案

Laravel Excel 底层的 Upsert 能力直接调用 Eloquent/QueryBuilder 的原生upsert方法,数据库层面不会直接返回区分插入、更新的行数统计,需要通过批次预处理的方式自行计数,实现步骤如下:

  • 第一步:在导入类中初始化计数属性
    在实现了WithUpserts接口的导入类中,定义两个公共属性分别存储插入、更新的累计行数,初始值设为0:

    namespace App\Imports;
    
    use Maatwebsite\Excel\Concerns\WithUpserts;
    use App\Models\YourTargetModel;
    
    class BusinessDataImport implements WithUpserts
    {
        // 累计插入行数
        public int $insertedCount = 0;
        // 累计更新行数
        public int $updatedCount = 0;
    
        // 原有方法保持不变
        public function uniqueBy()
        {
            // 返回你配置的upsert唯一判断字段,支持单字段/多字段数组
            return 'sku';
        }
    
        public function model(array $row)
        {
            return new YourTargetModel([
                // 原有字段映射逻辑
            ]);
        }
    }
    
  • 第二步:接入批量插入能力,注册批次前置事件做统计
    实现WithBatchInserts、WithEvents接口,在每一批数据写入数据库前,提前比对当前批次的唯一键和数据库已存在数据,分别累加两类行数:

    use Maatwebsite\Excel\Concerns\WithBatchInserts;
    use Maatwebsite\Excel\Concerns\WithEvents;
    use Maatwebsite\Excel\Events\BeforeBatchImport;
    use Illuminate\Support\Collection;
    
    class BusinessDataImport implements WithUpserts, WithBatchInserts, WithEvents
    {
        public int $insertedCount = 0;
        public int $updatedCount = 0;
    
        // 配置单批次写入行数,根据服务器性能调整即可
        public function batchSize(): int
        {
            return 200;
        }
    
        // 注册事件回调
        public function registerEvents(): array
        {
            return [
                BeforeBatchImport::class => function (BeforeBatchImport $event) {
                    $batchRows = $event->getDelegate()->getRows();
                    if (!$batchRows instanceof Collection || $batchRows->isEmpty()) {
                        return;
                    }
    
                    $uniqueColumns = (array)$this->uniqueBy();
                    // 统计当前批次有效数据行数
                    $validRowCount = $batchRows->filter(function ($row) use ($uniqueColumns) {
                        foreach ($uniqueColumns as $col) {
                            if (empty($row->{$col})) return false;
                        }
                        return true;
                    })->count();
    
                    // 查询当前批次中已存在于数据库的记录数,即本批次待更新行数
                    $existedQuery = $this->model();
                    foreach ($uniqueColumns as $col) {
                        $colValues = $batchRows->pluck($col)->filter()->unique()->toArray();
                        $existedQuery = $existedQuery->whereIn($col, $colValues);
                    }
                    $existedCount = $existedQuery->count();
    
                    // 累加计数
                    $this->updatedCount += $existedCount;
                    $this->insertedCount += $validRowCount - $existedCount;
                },
            ];
        }
    
        // 原有uniqueBy、model方法保持不变
        public function uniqueBy()
        {
            return 'sku';
        }
    
        public function model(array $row)
        {
            return new YourTargetModel([]);
        }
    }
    
  • 第三步:导入执行完成后读取统计值
    实例化导入类执行导入操作后,直接访问类上的两个公共属性就能拿到最终计数:

    $import = new BusinessDataImport();
    \Maatwebsite\Excel\Facades\Excel::import($import, request()->file('import_file'));
    
    // 直接取数使用
    $insertTotal = $import->insertedCount;
    $updateTotal = $import->updatedCount;
    

注意事项:

  1. 该统计方案逻辑和Upsert的判断规则完全对齐,无并发写入场景下统计准确率100%;如果导入同时存在其他并发写入同表的操作,建议导入时加表锁避免计数偏差。
  2. 不要直接用数据库返回的Upsert影响行数做统计:以MySQL为例,Upsert操作返回的影响行数规则为「新增行记1、更新行字段有变更记2、更新行无字段变更记0」,无法直接准确映射实际插入、更新的行数。
  3. 如果使用复合唯一键做Upsert判断,上述代码已经做了兼容,不需要额外调整逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:03:21