
本文介绍如何将两个数据库查询结果(如商品主表与价格明细表)高效合并,生成以主键为索引、包含子数组的嵌套结构,特别适用于一对多关系且需保留无关联记录的场景。
本文介绍如何将两个数据库查询结果(如商品主表与价格明细表)高效合并,生成以主键为索引、包含子数组的嵌套结构,特别适用于一对多关系且需保留无关联记录的场景。
在实际开发中,常需将主表(如 pj_barang)与从表(如 pj_detailsupplier)关联后组织成树形结构——即每个主表记录携带其所有关联的从表数据作为子数组(如 'dataharga' => [...])。直接使用 SQL JOIN 并配合 PHP 数组重组,是兼顾性能与可读性的推荐方案。
✅ 正确思路:先查主表,再按主键映射从表数据
原始代码存在两个关键问题:
- 使用了 RIGHT JOIN 导致主表可能被过滤(应优先保证主表完整);
- 嵌套循环逻辑错误($result[$value['id_barang'] = $val["id_barang"]] 是赋值表达式,非合法键名),且未保留主表原始结构。
推荐做法:
- 单独查询主表(确保所有 barang 记录均被包含);
- 查询从表后,用 array_column($harga, 'id_barang') 构建主键索引;
- 利用 array_search() 快速定位匹配项,避免 O(n²) 循环;
- 使用引用 &$value 直接向主表元素注入 dataharga 子数组。
✅ 示例代码(已优化可直接复用)
// 1. 查询主表(商品信息)
$barang = $this->db
->select('id_barang, nama_barang, merk')
->where('dihapus', 'tidak')
->get('pj_barang')
->result_array();
// 2. 查询从表(价格信息),不加 JOIN,保持数据纯净
$harga = $this->db
->select('id_barang, harga')
->get('pj_detailsupplier')
->result_array();
// 3. 构建 id_barang → 索引映射(支持一对多:同一 id_barang 可能有多条价格)
$idToHarga = [];
foreach ($harga as $item) {
$idToHarga[$item['id_barang']][] = $item; // 注意:[] 实现追加,支持多条价格
}
// 4. 合并数据:为主表每项注入 dataharga 子数组
foreach ($barang as &$item) {
$id = $item['id_barang'];
$item['dataharga'] = $idToHarga[$id] ?? []; // 若无匹配,返回空数组(更合理)
}
unset($item); // 解除引用,避免意外修改
// 输出结果(符合预期结构)
print_r($barang);
⚠️ 关键注意事项
- 一对多支持:上述 [] 追加写法可自然处理一个商品对应多个供应商价格的情形,比原答案中仅取首个匹配项更健壮;
- 空关联处理:使用 ?? [] 替代 ['id_barang' => "", 'harga' => ""],语义更清晰(空数组表示“无价格”,而非伪造空记录);
- 性能优化:array_column() + array_search() 时间复杂度为 O(n),远优于双重循环的 O(n×m);
- SQL 层建议:若数据量极大且业务允许,也可考虑单次 LEFT JOIN 查询后在 PHP 层分组,但需注意重复主表字段带来的冗余:
// 替代方案(单次查询 + PHP 分组)
$this->db->select('b.*, h.harga');
$this->db->from('pj_barang b');
$this->db->join('pj_detailsupplier h', 'b.id_barang = h.id_barang', 'left');
$this->db->where('b.dihapus', 'tidak');
$result = $this->db->get()->result_array();
// 再用 group_by_key() 函数分组(需自行实现或使用 array_reduce)
✅ 总结
正确实现“主表+子数组”结构的核心在于:以主表为基准,用哈希映射高效挂载从表数据。避免在循环中反复搜索、杜绝语法错误赋值,并根据业务需求决定是否支持一对多及空值语义。本方案简洁、高效、可维护,适用于 CodeIgniter 3/4 及通用 PHP 环境。











