关联policy与policy_case表,如何避免父数据重复并嵌套展示子数据
实现policy父表嵌套policy_case子表数据的解决方案
问题背景
需要将policy作为父表、policy_case作为子表,通过policy.id与policy_case.policy_id关联,实现父数据下嵌套展示子数据的结构。现有CodeIgniter关联查询会导致父表字段(如title、description)随子表条数重复,直接循环渲染会重复显示父数据,无法实现嵌套效果。
问题原因
关联查询(JOIN)会生成父表与子表的笛卡尔积结果,每条父数据会和对应子数据一一匹配,因此父表内容会重复出现,次数等于对应子数据的条数。
解决方案
方案一:分步查询(适合数据量较小场景)
先查询所有父表数据,再循环查询每个父数据对应的子表数据,直接构建嵌套结构:
控制器代码
// 查询所有政策数据(可根据open_flg过滤已发布内容) $this->db->select('id, title, description, open_flg, open_date'); $this->db->from('policy'); $this->db->where('open_flg', 1); $policies = $this->db->get()->result_array(); // 为每个政策绑定对应的案例数据 foreach ($policies as &$policy) { $this->db->select('id as case_id, title as case_title, contents as case_contents, open_flg, open_date'); $this->db->from('policy_case'); $this->db->where('policy_id', $policy['id']); $this->db->where('open_flg', 1); $policy['cases'] = $this->db->get()->result_array(); } $data['policies'] = $policies;
视图代码
<?php foreach ($policies as $policy) { ?> <div class="policy-wrapper"> <h2><?php echo $policy['title']; ?></h2> <p><?php echo $policy['description']; ?></p> <?php if (!empty($policy['cases'])) { ?> <div class="case-list"> <?php foreach ($policy['cases'] as $case) { ?> <div class="case-item"> <h3><?php echo $case['case_title']; ?></h3> <p><?php echo $case['case_contents']; ?></p> </div> <?php } ?> </div> <?php } ?> </div> <?php } ?>
方案二:单查询后整理数组(适合数据量较大场景)
执行一次关联查询后,通过PHP代码将重复的父数据合并,把子数据嵌套到父数据数组中:
控制器代码
// 执行关联查询 $this->db->select('policy.id, policy.title, policy.description, case.id as case_id, case.title as case_title, case.contents as case_contents'); $this->db->from('policy'); $this->db->join('policy_case case', 'case.policy_id = policy.id'); $this->db->where('policy.open_flg', 1); $this->db->where('case.open_flg', 1); $rawResult = $this->db->get()->result_array(); // 整理为嵌套结构 $policies = []; foreach ($rawResult as $item) { $policyId = $item['id']; // 初始化父数据 if (!isset($policies[$policyId])) { $policies[$policyId] = [ 'id' => $item['id'], 'title' => $item['title'], 'description' => $item['description'], 'cases' => [] ]; } // 添加子案例数据 $policies[$policyId]['cases'][] = [ 'case_id' => $item['case_id'], 'case_title' => $item['case_title'], 'case_contents' => $item['case_contents'] ]; } // 转换为索引数组(适配视图循环) $data['policies'] = array_values($policies);
视图代码
与方案一的视图代码完全一致。
方案对比
- 方案一:代码逻辑清晰,易于维护,但会产生N+1次查询(N为父数据条数),数据量大时性能下降明显。
- 方案二:仅执行1次数据库查询,性能更优,但需要额外的数组处理逻辑,代码复杂度稍高。
内容的提问来源于stack exchange,提问作者Toru Kawahata
相关产品推荐
相关产品推荐

