CodeIgniter多表查询结果优化:合并同一讲师的日程数据
解决CodeIgniter中一对多关联查询的结果嵌套问题
嘿,这个问题我熟!你现在遇到的是关联查询中一对多关系导致的重复父记录问题,想要把同一讲师的多条日程嵌套成子数组,其实可以通过两种常见方式实现,我给你详细说下:
方法一:分两次查询(先查讲师,再查对应日程)
这种方式逻辑清晰,适合数据量不大的场景,先获取所有符合条件的讲师基础信息,再逐个查询他们的日程并嵌套进去:
public function getDocent() { $roles = 'Docent'; // 第一步:获取所有符合角色的讲师基础信息 $docents_query = $this->db->select('id, name, surname') ->from('Persons') ->where('roles', $roles) ->get(); $docents = $docents_query->result_array(); // 第二步:遍历每个讲师,查询对应的空闲日程 foreach ($docents as &$docent) { $agenda_query = $this->db->select('date, start_at, end_at') ->from('Agenda') ->where('docent_id', $docent['id']) ->where('free', 'true') ->get(); // 把日程嵌套为子数组 $docent['agenda'] = $agenda_query->result_array(); } return $docents; }
注意:如果需要保留没有任何日程的讲师,这里不需要用关联查询,直接分两次查即可,没有日程的讲师agenda字段会是一个空数组。
方法二:一次查询后重组数组(避免N+1查询)
如果讲师数量较多,分两次查询会产生N+1的数据库请求,这时可以先执行一次关联查询,再在PHP里手动重组结果数组:
public function getDocent() { $roles = 'Docent'; // 执行关联查询获取所有原始数据 $query = $this->db->select('Persons.id, Persons.name, Persons.surname, Agenda.date, Agenda.start_at, Agenda.end_at') ->from('Persons') ->join('Agenda', 'Persons.id = Agenda.docent_id', 'INNER') ->where('Agenda.free', 'true') ->where('roles', $roles) ->get(); $raw_results = $query->result_array(); // 初始化重组后的数组 $formatted_docents = []; // 遍历原始数据,按讲师ID分组嵌套日程 foreach ($raw_results as $row) { $docent_id = $row['id']; // 如果该讲师还没被添加到结果数组,先写入基础信息 if (!isset($formatted_docents[$docent_id])) { $formatted_docents[$docent_id] = [ 'id' => $row['id'], 'name' => $row['name'], 'surname' => $row['surname'], 'agenda' => [] ]; } // 把当前日程添加到对应讲师的子数组中 $formatted_docents[$docent_id]['agenda'][] = [ 'date' => $row['date'], 'start_at' => $row['start_at'], 'end_at' => $row['end_at'] ]; } // 将关联数组转为索引数组(符合你想要的数组结构) return array_values($formatted_docents); }
说明:这种方式只需要一次数据库查询,性能更优;如果要保留无日程的讲师,把INNER JOIN改成LEFT JOIN即可,无日程的讲师agenda字段会是空数组。
控制器无需修改
你的控制器代码保持原样就行,返回的结果会自动变成每个讲师对应一条数据,日程嵌套在agenda子数组里,最终只会返回2个元素的数组,完全符合你的需求~
内容的提问来源于stack exchange,提问作者Jack23
相关产品推荐
相关产品推荐

