CodeIgniter3导入Excel到MySQL时如何检测跳过重复数据并提示
CodeIgniter3 Excel导入重复数据拦截实现方案
实现逻辑分三层:数据库唯一约束兜底、Excel内数据去重、与库内已有数据去重,同时收集重复条目信息做前端提示,重复数据自动跳过不入库。
1. 前置配置:添加数据库唯一索引
首先在MySQL的user表上,根据你的重复判定规则添加唯一索引,这是避免脏数据的核心保障,以常用的email作为唯一判定字段为例,执行以下SQL:
-- 单字段唯一:email重复即判定为重复数据 ALTER TABLE `user` ADD UNIQUE INDEX `uk_email` (`email`); -- 如果是多字段联合判定重复(例如姓名+手机号同时重复才算重复),可执行对应联合索引语句 -- ALTER TABLE `user` ADD UNIQUE INDEX `uk_name_mobile` (`name`, `mobile`);
2. 改造控制器导入逻辑
原逻辑未做任何去重判断直接批量入库,改造后增加两层去重、重复信息收集、提示信息暂存能力,替换后的控制器代码如下:
public function import_excel(){ // 加载session库用于跨跳转存提示,若已经在autoload中配置可省略 $this->load->library('session'); if(isset($_FILES["fileExcel"]["name"])){ $path=$_FILES["fileExcel"]["tmp_name"]; $object=PHPExcel_IOFactory::load($path); foreach($object->getWorksheetIterator() as $worksheet) { $highestRow=$worksheet->getHighestRow(); // 初始化待入库数组、重复记录数组、Excel内唯一字段暂存数组 $temp_data = []; $duplicate_list = []; $excel_unique_keys = []; $unique_field = 'email'; // 这里改成你判定重复的唯一字段,和数据库索引对应 for($row=2; $row<=$highestRow; $row++) { $password=$worksheet->getCellByColumnAndRow(4,$row)->getValue(); $name=$worksheet->getCellByColumnAndRow(1, $row)->getValue(); $company=$worksheet->getCellByColumnAndRow(3,$row)->getValue(); $email=strtolower($worksheet->getCellByColumnAndRow(2, $row)->getValue()); $mobile=$worksheet->getCellByColumnAndRow(5,$row)->getValue(); $level=$worksheet->getCellByColumnAndRow(6,$row)->getValue(); $active=$worksheet->getCellByColumnAndRow(7,$row)->getValue(); $row_data = array( 'name'=>$name, 'company'=>$company, 'email'=>$email, 'password'=>password_hash($password,PASSWORD_DEFAULT), 'mobile'=>$mobile, 'level'=>$level, 'active'=>$active ); // 第一层:判断Excel内部是否存在重复 if(in_array($row_data[$unique_field], $excel_unique_keys)){ $duplicate_list[] = "第{$row}行数据:{$row_data[$unique_field]} 与Excel内其他条目重复,已跳过"; continue; } $excel_unique_keys[] = $row_data[$unique_field]; $temp_data[] = $row_data; } // 第二层:判断与数据库已有数据是否重复 if(!empty($temp_data)){ // 批量查询库中已存在的唯一值 $exist_records = $this->m_data->get_exist_keys($excel_unique_keys, $unique_field); $exist_keys = array_column($exist_records, $unique_field); $valid_data = []; foreach($temp_data as $item){ if(in_array($item[$unique_field], $exist_keys)){ $duplicate_list[] = "数据:{$item[$unique_field]} 已在系统中存在,已跳过"; continue; } $valid_data[] = $item; } // 有效数据入库 $insert_count = 0; if(!empty($valid_data)){ $insert_count = $this->m_data->insert($valid_data); } // 组装提示信息存入session flashdata $msg = "本次导入成功{$insert_count}条数据"; if(!empty($duplicate_list)){ $msg .= ",跳过".count($duplicate_list)."条重复数据:<br>".implode('<br>', $duplicate_list); } $this->session->set_flashdata('import_msg', $msg); } redirect('userlist'); } } }
3. 改造模型层代码
新增查询已存在唯一键的方法,调整插入方法返回实际入库条数:
// 批量查询已存在的唯一字段记录 public function get_exist_keys($keys, $field = 'email'){ return $this->db->select($field) ->from('user') ->where_in($field, $keys) ->get() ->result_array(); } // 批量插入有效数据,返回插入行数 public function insert($temp_data){ $this->db->insert_batch('user',$temp_data); return $this->db->affected_rows(); }
4. 列表页展示导入提示
在userlist对应的控制器方法中,把session存储的提示信息传递给视图,在视图对应位置输出即可:
// userlist方法中取提示 $data['import_msg'] = $this->session->flashdata('import_msg'); $this->load->view('user_list', $data);
视图中对应位置输出提示:
<?php if(!empty($import_msg)):?> <div class="alert alert-info"> <?php echo $import_msg;?> </div> <?php endif;?>
注意事项
- 数据库唯一索引必须添加,仅靠PHP代码去重无法应对并发场景下的脏数据写入
- 如果单批次导入Excel行数超过1万条,建议拆分查询库内已有key的逻辑,分批查询避免PHP内存溢出
- 可根据业务需求调整重复判定字段,只需要修改代码中
$unique_field的取值、对应创建匹配的唯一索引即可
内容的提问来源于stack exchange,提问作者dhoeng
相关产品推荐
相关产品推荐

