PHP查询年度服务数据时如何补全数组缺失年份的0值条目
问题背景
- 需求为统计合同内住宿(HEBERGEMENT)、餐饮(RESTAURATION)两类服务的年度营收总额,结果存入数组后传递给JavaScript渲染动态图表,当前基础查询功能运行正常
- 现存故障:部分年份无对应类别的服务数据时,原有循环逻辑不会补全缺失条目,导致两个分类的数组长度不一致、年份顺序不匹配,传递到前端后图表列错位,无法正常渲染
原有实现代码
while ($data = $requete1->fetch()) { // Hébergement : if($data['P_TYPE']=="HEBERGEMENT"){ $hebergement[] = array("label"=> $data['ANNEE'], "y"=> $data['ca_total']); } // Restauration : if($data['P_TYPE']=="RESTAURATION"){ $restauration[] = array("label"=> $data['ANNEE'], "y"=> $data['ca_total']); } }
预期输出结构
统计年份范围内,两类服务对应的数组需包含所有年份条目,无对应数据的年份y值填充为0,参考结构如下:
// Hébergement années non comprises en bdd : $hebergement[] = array("label"=> "2021", "y"=> 68279); $hebergement[] = array("label"=> "2020", "y"=> 30457); $hebergement[] = array("label"=> "2019", "y"=> 0); $hebergement[] = array("label"=> "2018", "y"=> 57993); $hebergement[] = array("label"=> "2017", "y"=> 49702); $hebergement[] = array("label"=> "2016", "y"=> 45493); $hebergement[] = array("label"=> "2015", "y"=> 38460); // Restauration années non comprises en bdd : $restauration[] = array("label"=> "2021", "y"=> 12117); $restauration[] = array("label"=> "2020", "y"=> 697); $restauration[] = array("label"=> "2019", "y"=> 2687); $restauration[] = array("label"=> "2018", "y"=> 0); $restauration[] = array("label"=> "2017", "y"=> 40); $restauration[] = array("label"=> "2016", "y"=> 350); $restauration[] = array("label"=> "2015", "y"=> 200);
原有补全逻辑的问题
之前尝试的补全代码依赖单次循环内的临时年份差值判断,没有先固定完整的统计年份范围,也没有对两类数据做独立的键值映射,会出现补错位、漏补的情况,无法达到预期效果。
正确实现方案
核心逻辑分三步:先确定完整统计年份范围、给两类数据初始化所有年份的默认值为0、遍历查询结果覆盖实际营收值,最后按统一顺序生成前端需要的数组。
// -------------------------- // 步骤1:确定统计年份范围 // -------------------------- // 方式1:手动指定起止年份,根据业务需求修改 $startYear = 2015; $endYear = 2021; /* // 方式2:自动从查询结果中取最小/最大年份作为范围,不需要手动写死 $allData = $requete1->fetchAll(); // 一次性取出所有结果,不能用fetch多次遍历 $years = array_column($allData, 'ANNEE'); $startYear = min($years); $endYear = max($years); */ // 初始化两类数据的临时映射,以年份为键,默认营收为0 $hebergementMap = []; $restaurationMap = []; for ($y = $startYear; $y <= $endYear; $y++) { $hebergementMap[$y] = 0; $restaurationMap[$y] = 0; } // -------------------------- // 步骤2:遍历查询结果填充实际值 // -------------------------- // 如果用方式2自动取年份,这里把$requete1->fetch()改成遍历$allData即可 while ($data = $requete1->fetch()) { $year = $data['ANNEE']; // 跳过不在统计范围内的异常数据 if ($year < $startYear || $year > $endYear) { continue; } if ($data['P_TYPE'] == "HEBERGEMENT") { $hebergementMap[$year] = $data['ca_total']; } if ($data['P_TYPE'] == "RESTAURATION") { $restaurationMap[$year] = $data['ca_total']; } } // -------------------------- // 步骤3:按统一顺序生成前端需要的数组 // -------------------------- $hebergement = []; $restauration = []; // 此处从最大年份倒序遍历,和示例的年份排序保持一致;需要正序就改成for($y = $startYear; $y <= $endYear; $y++) for ($y = $endYear; $y >= $startYear; $y--) { $hebergement[] = [ "label" => (string)$y, "y" => $hebergementMap[$y] ]; $restauration[] = [ "label" => (string)$y, "y" => $restaurationMap[$y] ]; }
注意:如果选择自动从查询结果取年份范围的方案,必须用fetchAll()一次性取出所有结果集,不能重复调用fetch()遍历两次,否则第二次遍历拿不到数据。
内容的提问来源于stack exchange,提问作者user19487444
相关产品推荐
相关产品推荐

