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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 15:33:14