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

PhpSpreadsheet:重复MySQL记录写入Excel对应列的实现问题

解决重复DNI的Excel写入分组问题

核心需求回顾

已实现从MySQL导出数据到Excel,现有规则:

  • 当tipoActividad=1时,写入DESCRIPCION和DIA到对应列组
  • 当tipoActividad=2时,写入NOMBRE_SESION和DIA到对应列组
  • 需补充逻辑:若Excel中已存在某DNI的行,将当前记录写入该行的下一组空列(例:AE、AF已填充时,写入AG、AH)

MySQL表结构示例

CREATE TABLE actividades (
    id INT AUTO_INCREMENT PRIMARY KEY,
    DNI VARCHAR(20) NOT NULL,
    tipoActividad TINYINT(1) NOT NULL,
    DESCRIPCION TEXT,
    NOMBRE_SESION VARCHAR(100),
    DIA DATE NOT NULL
);

解决方案(基于PhpSpreadsheet实现)

核心思路

  1. 先遍历Excel现有数据,构建DNI-行号映射数组,快速定位重复DNI的位置
  2. 处理每条MySQL记录时:
    • 若DNI已存在:在对应行中从初始列组开始,找到第一个双列都为空的组写入
    • 若DNI不存在:新增一行,写入DNI和第一组数据,同时更新映射数组

修改后的PHP代码

<?php
require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

// 初始化Excel对象(读取已有文件请用IOFactory::load())
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// 配置参数:表头在第1行,数据从第2行开始;初始列组为AE(索引30)、AF(索引31)(PhpSpreadsheet列索引从0开始)
$startRow = 2;
$initialColGroupStart = 30;
$highestRow = $sheet->getHighestRow();

// 1. 构建DNI-行号映射
$dniRowMap = [];
for ($row = $startRow; $row <= $highestRow; $row++) {
    $dni = $sheet->getCellByColumnAndRow(0, $row)->getValue(); // 假设DNI在A列(索引0)
    if (!empty($dni)) {
        $dniRowMap[$dni] = $row;
    }
}

// 2. 从MySQL获取数据
$pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'password');
$stmt = $pdo->query("SELECT DNI, tipoActividad, DESCRIPCION, NOMBRE_SESION, DIA FROM actividades");
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 3. 逐条处理记录
foreach ($records as $record) {
    $dni = $record['DNI'];
    $tipo = $record['tipoActividad'];
    $dia = $record['DIA'];
    $content = $tipo == 1 ? $record['DESCRIPCION'] : $record['NOMBRE_SESION'];

    if (isset($dniRowMap[$dni])) {
        // DNI已存在,查找该行下一组空列
        $targetRow = $dniRowMap[$dni];
        $currentCol = $initialColGroupStart;
        
        while (true) {
            $col1Val = $sheet->getCellByColumnAndRow($currentCol, $targetRow)->getValue();
            $col2Val = $sheet->getCellByColumnAndRow($currentCol + 1, $targetRow)->getValue();
            
            if (empty($col1Val) && empty($col2Val)) {
                // 找到空组,写入数据
                $sheet->setCellValueByColumnAndRow($currentCol, $targetRow, $content);
                $sheet->setCellValueByColumnAndRow($currentCol + 1, $targetRow, $dia);
                break;
            }
            $currentCol += 2; // 跳到下一组列
        }
    } else {
        // DNI不存在,新增行写入
        $targetRow = ++$highestRow;
        // 写入DNI到A列
        $sheet->setCellValueByColumnAndRow(0, $targetRow, $dni);
        // 写入第一组数据
        $sheet->setCellValueByColumnAndRow($initialColGroupStart, $targetRow, $content);
        $sheet->setCellValueByColumnAndRow($initialColGroupStart + 1, $targetRow, $dia);
        // 更新映射
        $dniRowMap[$dni] = $targetRow;
    }
}

// 保存文件
$writer = new Xlsx($spreadsheet);
$writer->save('exported_actividades.xlsx');
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
?>

关键细节说明

  • 映射数组优化:$dniRowMap避免了每次查找重复DNI时遍历整个Excel,大幅提升处理效率
  • 列组判断:只有当一组的两个单元格都为空时才视为可写入的空组,避免覆盖已有数据
  • 列索引对应:PhpSpreadsheet使用0-based列索引,需注意Excel列名与索引的转换(如AE列对应索引30)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:19:54