CSV生成异常问题:如何用ArticleStock.csv中的产品信息替换订单CSV对应字段
CSV生成异常问题:如何用ArticleStock.csv中的产品信息替换订单CSV对应字段
我仔细看了你的代码和问题描述,现在的核心问题是你只在第一次处理订单行时遍历了一遍ArticleStock.csv,之后的订单行根本没机会再匹配CSV里的产品信息,而且这种逐行循环匹配的方式效率低还容易漏数据。咱们来一步步解决这个问题:
问题根源拆解
- 你把ArticleStock.csv的数据存在了普通数组
$CSVData里,每次处理订单行时,内层的while ($rowcsv < $numRows)循环会把$rowcsv一直加到末尾,后面的订单行再进来时,这个循环直接不执行,自然匹配不到产品信息。 - 没有把CSV数据做成以产品reference为键的关联数组,每次匹配都要遍历整个CSV,既低效又容易出错。
修复后的完整代码
<?php require_once 'dbconfig.php'; try { $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); $sql = 'SELECT o.id_order , c.id_customer, c.firstname, c.lastname, a.address1, a.address2, a.postcode, a.city,a.phone, c.email, a.phone_mobile, od.product_id, od.product_name, p.reference, od.product_quantity, od.product_price, o.total_paid_tax_incl, c.id_customer, op.date_add, op.amount, op.payment_method FROM mod582_orders o INNER JOIN mod582_customer c ON o.id_customer = c.id_customer INNER JOIN mod582_address a ON o.id_address_delivery = a.id_address INNER JOIN mod582_order_detail od ON o.id_order = od.id_order INNER JOIN mod582_order_payment op ON o.reference = op.order_reference INNER JOIN mod582_product p ON p.id_product = od.product_id WHERE CAST(o.date_add AS DATE) like "2022-12%";'; $r = $pdo->query($sql); $tab = []; $tab[] = [ 'ORDNOORDER', 'ORDREFCUSORDER', 'ORDNOCOSTNUMBER', 'ORDNOCUSTOMER', 'ORDCUSTOMERCODE', 'ORDCUSCAT', 'ORDTYPE', 'ORDCURRENCY', 'ORDCURRENCYRATE', 'ORDDESIGNATION', 'ORDREPCODE', 'ORDPORT', 'ORDPORTTYPE', 'ORDPORTRATE', 'DEONOORDER', 'DEOCOMMENT', 'DEOCOUNTRY', 'DEONAME', 'DEOFIRSTNAME', 'DEOADDRESS1', 'DEOADDRESS2', 'DEOZIPCODE', 'DEOCITY', 'DEOPHONE', 'DEOMAIL', 'DEOPHONEPORTABLE', 'ODLNOORDER', 'ODLNOORDERLINE', 'ODLNOARTICLE', 'ODLARTDESIGN', 'REFERENCEPRODUIT', 'ODLQUANTITYORDER', 'ODLTTCCURUPRICE', 'ODLCODEPARCELLEFLEU', 'PAYNUMPAYMENT', 'PAYNOCUSTOMER', 'PAYNOORDER', 'PAYNOCURRENCY', 'PAYDATEPAYMENT', 'PAYPAYMENTTTCCUR', 'PAYCURRENCYRATE', 'PAYCONTREPARTIE' ]; $odrline = 0; $prevordernumber = 0; // 关键改进:把ArticleStock.csv加载成关联数组,用reference作为键 $articleStockMap = []; $file = fopen("ArticlesStock.csv", "r"); if ($file) { // 跳过CSV表头(如果你的CSV没有表头,就删掉这一行) fgets($file); while (($line = fgetcsv($file, 0, ";")) !== false) { // $line[0]是CSV里的产品ID(对应订单的reference),$line[2]是产品名称 $articleStockMap[$line[0]] = [ 'id' => $line[0], 'name' => $line[2] ]; } fclose($file); } while ($rs = $r->fetch(PDO::FETCH_ASSOC)) { $refproduit = $rs['reference']; // 直接从关联数组获取匹配的产品信息,没有匹配到就用原数据库的信息兜底 $matchedProduct = $articleStockMap[$refproduit] ?? [ 'id' => $rs['product_id'], 'name' => $rs['product_name'] ]; if ($prevordernumber != $rs['id_order']) { $odrline++; $baseDate = strtotime($rs['date_add']); $formatDate = date("d/m/Y", $baseDate); $tab[] = [ $rs['id_order'], $rs['id_order'], '17', '', 'AAA' . $rs['id_customer'], 'DET', 'O', 'EUR', '1', '', '115', 'D', 'P', '17', $rs['id_order'], '', 'FRA', $rs['firstname'], $rs['lastname'], $rs['address1'], $rs['address2'], $rs['postcode'], $rs['city'], $rs['phone'], $rs['email'], $rs['phone_mobile'], $rs['id_order'], $odrline, $matchedProduct['id'], $matchedProduct['name'], $rs['reference'], $rs['product_quantity'], $rs['product_price'], '', '', '', $rs['id_order'], 'EUR', $formatDate, $rs['amount'], '1', 'VIR' ]; } else { $tab[] = [ $rs['id_order'], $rs['id_order'], '17', '', 'AAA' . $rs['id_customer'], 'DET', 'O', 'EUR', '1', '', '115', 'D', 'P', '17', $rs['id_order'], '', 'FRA', $rs['firstname'], $rs['lastname'], $rs['address1'], $rs['address2'], $rs['postcode'], $rs['city'], $rs['phone'], $rs['email'], $rs['phone_mobile'], $rs['id_order'], $odrline, $matchedProduct['id'], $matchedProduct['name'], $rs['reference'], $rs['product_quantity'], $rs['product_price'], '', '', '', $rs['id_order'], '', '', '', '' ]; } $prevordernumber = $rs['id_order']; } // 写入CSV文件 $date = date('d-m-y'); $fichier_csv = new SplFileObject('Vinistoria/Out/Commande/commande_STOCK_' . $date . '.csv', 'w'); foreach ($tab as $ligne) { $fichier_csv->fputcsv($ligne, ';'); } } catch (PDOException $e) { die("Could not connect to the database $dbname :" . $e->getMessage()); }
关键改进点说明
- 关联数组存储CSV数据:把ArticleStock.csv的内容转成
$articleStockMap,键是产品的reference(也就是CSV第一列),这样每次匹配只需要O(1)的时间,高效又不会漏数据。 - 移除错误的内层循环:原来的内层
while循环会把CSV指针移到末尾,导致后续订单行无法匹配,现在直接通过关联数组查找,彻底解决这个问题。 - 兼容无匹配的情况:用
??运算符处理没有匹配到的产品,默认用数据库里的product_id和product_name,避免出现空值或者缺失数据。 - 使用
fgetcsv解析CSV:比fgets+explode更可靠,能自动处理CSV里的特殊字符(比如包含分号的字段)。
这样修改后,所有订单行都会正确匹配ArticleStock.csv里的产品信息,替换掉ODLNOARTICLE和ODLARTDESIGN字段,不会再出现只有部分数据显示的问题。
备注:内容来源于stack exchange,提问作者Gaiaryde
相关产品推荐
相关产品推荐

