
本文介绍在 CodeIgniter 中高效合并 barang(商品)与 harga(价格)两张表的数据,将多对一关系转换为以商品为主、价格为子数组的嵌套结构,并处理无匹配价格记录的边界情况。
本文介绍在 codeigniter 中高效合并 `barang`(商品)与 `harga`(价格)两张表的数据,将多对一关系转换为以商品为主、价格为子数组的嵌套结构,并处理无匹配价格记录的边界情况。
在实际开发中,常需将主表(如商品表 pj_barang)与其关联的从表(如供应商价格表 pj_detailsupplier)进行逻辑关联,并组织成层次化数组结构——即每个商品项携带其所有对应价格记录(可能为零条或多条)。直接使用 SQL JOIN 并不能天然满足“每个商品一个独立子数组”的需求,尤其当存在一对多关系且需保留无价格的商品时,必须在 PHP 层完成结构重组。
✅ 推荐实现方式:预构建索引 + 引用赋值
避免嵌套循环(O(n×m) 时间复杂度),应先将 $harga 按 id_barang 构建索引映射,再遍历 $barang 一次完成注入。以下是优化后的完整逻辑:
// 1. 查询主表(商品),过滤已删除记录
$barang = $this->db
->select('id_barang, nama_barang, merk')
->from('pj_barang')
->where('dihapus', 'tidak')
->get()
->result_array();
// 2. 查询从表(价格),仅需关联字段(注意:此处用 LEFT JOIN 更合理,确保获取所有有价格的记录)
$harga = $this->db
->select('id_barang, harga')
->from('pj_detailsupplier')
->get()
->result_array();
// 3. 构建 id_barang → 价格记录数组的映射(支持一对多!)
$hargaMap = [];
foreach ($harga as $h) {
$id = (string)$h['id_barang']; // 转为字符串避免类型混淆
if (!isset($hargaMap[$id])) {
$hargaMap[$id] = [];
}
$hargaMap[$id][] = $h; // 累积所有匹配价格
}
// 4. 遍历商品,注入 dataharga 子数组(含空数组兜底)
foreach ($barang as &$item) {
$id = (string)$item['id_barang'];
$item['dataharga'] = $hargaMap[$id] ?? [];
}
// 输出结果(符合预期结构:每个商品含 dataharga 数组,即使为空)
print_r($barang);
? 关键说明与注意事项
为什么不用 array_search + array_column?
原答案中 array_search(array_column(...)) 仅能匹配第一条价格记录,无法处理一对多场景(如某商品有多个供应商报价)。而本方案通过 $hargaMap[$id][] = $h 显式累积,天然支持多条价格。为何不推荐 RIGHT JOIN?
原查询中 RIGHT JOIN ... FROM pj_detailsupplier 实际会以价格表为主表,导致缺失价格的商品被排除。正确做法是:主查 pj_barang,再 LEFT JOIN 或单独查 pj_detailsupplier 后关联,确保所有有效商品均被保留。空价格项的处理
使用 ?? [](空合并操作符)替代硬编码 ['id_barang' => '', 'harga' => ''],语义更清晰,且避免污染数据结构(空数组比带空字符串的伪对象更安全、更易判断)。性能提示
若数据量较大(如商品 > 5000 条),建议在数据库层用 GROUP_CONCAT 或 JSON 函数预聚合,或启用 Redis 缓存映射关系,避免 PHP 层重复计算。
最终生成的 $barang 数组结构完全符合需求:每个元素包含原始商品字段 + dataharga 键,其值为该商品所有价格记录组成的数组(可为空),便于前端渲染多价格卡片、后台导出或进一步统计分析。











