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
相关产品推荐
相关产品推荐

