基于双数组ID比对的数据库更新与插入逻辑实现问题
解决方案
原代码的核心问题
- 每次循环数据库记录时都重新打开并读取整个CSV文件,导致重复处理数据,效率极低且会产生重复插入
- 更新语句存在语法错误:
$$N_utente是笔误,应为$N_utente - 逐行比对数据库与CSV的逻辑错误:同一个CSV记录会被多次判断(和每个数据库记录比对一次),产生大量无效操作与重复数据
正确实现步骤
- 先将数据库中所有已存在的
N_utente存入数组,用于快速查询 - 一次性读取并处理CSV文件,避免重复IO操作
- 对每个CSV记录,检查是否存在于数据库数组中,执行对应更新/插入操作
修正后的代码
// 1. 获取数据库中所有已存在的N_utente,存入数组 $existingIds = []; $query1 = $conn->prepare("SELECT N_utente FROM raddb.Areceber"); $query1->execute(); while($row = $query1->fetch(PDO::FETCH_ASSOC)){ $existingIds[$row["N_utente"]] = true; // 用键名存储ID,快速判断存在性 } // 2. 读取并处理CSV文件 $file = $_FILES["file"]["tmp_name"]; $file_open = fopen($file, "r"); // 若CSV有表头,先跳过表头行(根据实际情况调整) // fgetcsv($file_open, 1000, ","); while(($csv = fgetcsv($file_open, 1000, ",")) !== false){ $N_utente = $csv[1]; $Id = $csv[0]; // 假设Id_linha来自CSV第0列,根据实际情况修改 if(isset($existingIds[$N_utente])){ // 3. ID存在,执行更新操作(注意:原更新语句仅更新N_utente为相同值,无实际意义,建议修改为更新业务字段) $query = 'UPDATE Areceber SET /* 填写需要更新的字段,如字段名=? */ WHERE N_utente = ? '; $stmt = $conn->prepare($query); // 示例:若更新valor字段为100,写法为->execute([100, $N_utente]); $stmt->execute([$N_utente, $N_utente]); // 保留原逻辑的更新,可按需修改 }else{ // ID不存在,执行插入操作 $query = 'INSERT INTO Areceber (Id_linha, N_utente) VALUES (?, ?)'; $stmt = $conn->prepare($query); $stmt->execute([$Id, $N_utente]); } } fclose($file_open); // 记得关闭文件句柄
额外说明
- 如果更新需要修改业务字段(而非重复设置
N_utente),请调整UPDATE语句的字段部分,例如UPDATE Areceber SET valor=?, data_vencimento=? WHERE N_utente = ? - 可添加事务处理保证数据一致性:操作前执行
$conn->beginTransaction();,成功后执行$conn->commit();,出错时执行$conn->rollBack();
内容的提问来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

