
本文讲解如何将多个 MySQL 查询结果按门店分组,并嵌套封装为符合层级要求的 JSON 结构,核心是使用外层数组(如 "DATA")包裹每个门店的完整数据对象。
本文讲解如何将多个 mysql 查询结果按门店分组,并嵌套封装为符合层级要求的 json 结构,核心是使用外层数组(如 `"data"`)包裹每个门店的完整数据对象。
在 PHP 中处理多门店销售数据时,常需对同一张表执行多次查询(如汇总总额 + 分类明细),并将结果组织为清晰、可扩展的 JSON 层级结构。原始代码已能生成单个门店的 soldArticles 数组及 Prodavnica、Total 字段,但缺少统一的顶层容器(如 "DATA" 数组)来容纳所有门店对象——这正是前后端接口规范或前端渲染所需的关键结构。
要实现目标结构,关键在于:将每个门店的完整 $json 对象(而非其子元素)作为独立单元,追加到一个新的外层数组中。原始逻辑中 $json 是复用的关联数组,每次循环都会覆盖其内容;因此需在每次循环内构建一个独立的门店数据副本,并将其推入 DATA 数组。
以下是优化后的完整实现(含安全与可维护性增强):
<?php
// 初始化顶层容器
$response = ['DATA' => []];
for ($brojac = 0; $brojac < count($storeLocationID); $brojac++) {
$storeName = storeFullName($storeLocationID[$brojac]);
// ✅ 使用预处理语句防止 SQL 注入(强烈推荐)
$stmtTotal = $conn->prepare(
"SELECT SUM(art_ukupno) AS ukupno, art_nazivProdavnice
FROM tbl_ProdatiArtikli
WHERE art_datum BETWEEN ? AND ? AND art_nazivProdavnice = ?"
);
$stmtTotal->bind_param("ssi", $startDate, $endDate, $storeName);
$startDate = '2022-08-10';
$endDate = '2022-08-12';
$stmtTotal->execute();
$resultTotal = $stmtTotal->get_result();
$stmtDetail = $conn->prepare(
"SELECT art_kategorija, SUM(art_kolicina) AS Qty, SUM(art_ukupno) AS Total
FROM tbl_ProdatiArtikli
WHERE art_datum BETWEEN ? AND ? AND art_nazivProdavnice = ?
GROUP BY art_kategorija
ORDER BY art_kategorija ASC"
);
$stmtDetail->bind_param("ssi", $startDate, $endDate, $storeName);
$stmtDetail->execute();
$resultDetail = $stmtDetail->get_result();
// 构建单个门店对象(避免复用同一变量)
$storeData = [
'soldArticles' => [],
'Prodavnica' => $storeName,
'Total' => '0.00'
];
// 获取总金额
if ($rowTotal = $resultTotal->fetch_assoc()) {
$storeData['Total'] = (string)$rowTotal['ukupno'];
}
// 获取分类明细
while ($rowDetail = $resultDetail->fetch_assoc()) {
$storeData['soldArticles'][] = [
'Category' => (string)$rowDetail['art_kategorija'],
'Qty' => (string)$rowDetail['Qty'],
'Total' => (string)$rowDetail['Total']
];
}
// ✅ 将当前门店对象推入 DATA 数组(核心修正点)
$response['DATA'][] = $storeData;
}
// 输出标准化 JSON(UTF-8 安全 + 格式化可选)
header('Content-Type: application/json; charset=utf-8');
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?>关键改进说明:
立即学习“PHP免费学习笔记(深入)”;
-
结构隔离:每次循环创建独立的
$storeData数组,彻底避免键值覆盖问题; -
安全加固:采用
mysqli::prepare()防止 SQL 注入,替代危险的字符串拼接; - 类型明确:对数值字段显式转为字符串,确保 JSON 中无数字类型歧义(尤其前端解析时);
-
健壮性提升:增加
fetch_assoc()判空逻辑,避免空结果导致 Notice 错误; -
语义清晰:顶层键名
DATA直观表达数据集合含义,符合 RESTful 接口惯例。
注意事项:
⚠️ 原始代码中嵌套 while 循环存在逻辑缺陷:内层 mysqli_fetch_array($result1) 在首次循环后指针已耗尽,后续门店将无法获取明细数据(因 $result1 未重置)。本方案通过重新执行预处理语句彻底规避该问题。
⚠️ 若门店数量较大,建议考虑单次 JOIN 查询或缓存机制以提升性能,而非循环多次查询。
最终输出将严格符合预期结构:{"DATA":[{...},{...}]},每个子对象包含完整的 soldArticles、Prodavnica 和 Total 字段,便于前端通过 response.DATA.forEach(store => ...) 进行遍历渲染。



















