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

PHP PDO多对多查询生成多余列 如何将关联发票ID合并到单个单元格

问题根因

多余列来自错误的循环逻辑:渲染单条人员行时,你嵌套遍历了全量发票关联结果集,每遍历1条记录就输出1个<td>单元格。假设分组后共查到M条人员-发票聚合记录,每一行人员就会生成M个发票相关单元格,仅1个单元格匹配当前人员ID填入发票号,其余全部填充-,自然产生大量冗余空列。

修复方案

最小改动版(无需调整现有SQL)

先把发票结果集重组为以人员ID为键的映射数组,渲染人员行时直接匹配对应值,每个人员仅输出1个发票单元格,从根源上避免多余列生成。

替换原有前端渲染代码为以下内容:

$table = 'people';
$results = $data->viewdatamodel($table);
$invoices = $data->viewdatajoin($table);

// 重组发票数组,键为人员ID,值为关联发票ID串
$invoiceMap = [];
foreach ($invoices as $invItem) {
    $invoiceMap[$invItem['people_id']] = $invItem['invoice_id'];
}
?>
<table border="1">
    <?php
    $no = 1;
    foreach ($results as $result) {
    ?>
    <tr>
        <?php
        echo '<td>'.$no.'</td>';
        echo '<td style="display: none;">'.$result['id'].'</td>';
        echo '<td>'.$result['name'].'</td>';
        echo '<td>'.$result['email'].'</td>';
        // 仅输出1个发票单元格,匹配到关联发票则展示,否则显示-
        echo '<td>'.($invoiceMap[$result['id']] ?? '-').'</td>';
        ?>
        <td>
            <a href="edit.php?id=<?php echo $result['id']?>&table=<?php echo $table;?>">EDIT</a>|
            <a href="lib/process.php?action=delete&id=<?php echo $result['id']?>&table=<?php echo $table;?>">DELETE</a>
        </td>
    </tr>
    <?php
        $no++;
    }
    ?>
</table>

优化版(推荐,减少冗余逻辑)

原有viewdatajoin方法的SQL存在逻辑缺陷:按people_id分组时直接查询inv.status会返回随机一条关联发票的状态值,不符合聚合预期。建议直接通过LEFT JOIN一次查询出所有人员及关联发票数据,省去PHP层二次匹配的逻辑。

替换模型层查询方法为:

public function getPeopleWithLinkedInvoices()
{
    $sql = "SELECT
        p.id,
        p.name,
        p.email,
        GROUP_CONCAT(pi.inv_id SEPARATOR ', ') AS invoice_ids
    FROM people p
    LEFT JOIN people_inv pi ON p.id = pi.people_id
    LEFT JOIN inv i ON pi.inv_id = i.id
    GROUP BY p.id, p.name, p.email
    ORDER BY p.id DESC";
    $query = $this->db->query($sql);
    $query->execute();
    return $query->fetchAll(PDO::FETCH_ASSOC);
}

对应前端渲染代码可简化为:

$peopleList = $data->getPeopleWithLinkedInvoices();
?>
<table border="1">
    <?php
    $no = 1;
    foreach ($peopleList as $item) {
    ?>
    <tr>
        <td><?php echo $no;?></td>
        <td style="display: none;"><?php echo $item['id'];?></td>
        <td><?php echo $item['name'];?></td>
        <td><?php echo $item['email'];?></td>
        <td><?php echo $item['invoice_ids'] ?: '-';?></td>
        <td>
            <a href="edit.php?id=<?php echo $item['id'];?>&table=people">EDIT</a>|
            <a href="lib/process.php?action=delete&id=<?php echo $item['id'];?>&table=people">DELETE</a>
        </td>
    </tr>
    <?php
        $no++;
    }
    ?>
</table>
补充说明
  • 如果需要实现你提到的[1, 2]展示格式,只需要在输出发票ID时拼接前后括号即可,例如将发票单元格输出代码改为echo '<td>['.($invoiceMap[$result['id']] ?? '-').']</td>';
  • MySQL的GROUP_CONCAT默认最大长度为1024字符,如果单个人员关联发票数量较多,可在执行查询前先运行SET SESSION group_concat_max_len = 10240;调整长度限制,避免发票ID被截断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 03:12:14