
本文详解如何将多次数据库查询生成的店铺销售数据,统一包装进名为 "data" 的顶层数组中,形成符合 api 规范的嵌套 json 响应结构。
本文详解如何将多次数据库查询生成的店铺销售数据,统一包装进名为 "data" 的顶层数组中,形成符合 api 规范的嵌套 json 响应结构。
在构建多店铺销售统计类 API 时,常需对每个门店(如 Store 01、Store 02)分别执行聚合查询,并将结果按统一格式组织为层级化 JSON。原始代码的问题在于:所有店铺的数据均写入同一 $json 数组,导致后一次循环覆盖前一次的 "Prodavnica" 和 "Total" 字段,且最终输出缺乏顶层容器(如 "DATA"),无法体现“多店铺集合”的语义。
正确做法是:为每个店铺构造独立的数据单元(子数组),再将其逐个追加至顶层 "DATA" 数组中。关键在于避免复用同一 $json 变量,而应在每次循环内新建局部结构。
以下是优化后的完整实现(含安全加固与可读性提升):
<?php
// 初始化顶层容器
$response = ['DATA' => []];
for ($i = 0; $i < count($storeLocationID); $i++) {
$storeName = storeFullName($storeLocationID[$i]);
// ✅ 使用预处理语句防止 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();
$stmtDetails = $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"
);
$stmtDetails->bind_param("ssi", $startDate, $endDate, $storeName);
$stmtDetails->execute();
$resultDetails = $stmtDetails->get_result();
// 构建单个店铺对象
$storeData = [
'soldArticles' => [],
'Prodavnica' => $storeName,
'Total' => '0.00'
];
// 获取总销售额
if ($rowTotal = $resultTotal->fetch_assoc()) {
$storeData['Total'] = (string)$rowTotal['ukupno'];
}
// 获取分类明细
while ($rowDetail = $resultDetails->fetch_assoc()) {
$storeData['soldArticles'][] = [
'Category' => (string)$rowDetail['art_kategorija'],
'Qty' => (string)$rowDetail['Qty'],
'Total' => (string)$rowDetail['Total']
];
}
// ✅ 将当前店铺数据推入顶层 DATA 数组
$response['DATA'][] = $storeData;
}
// 输出标准化 JSON(保留中文字符,格式化可选)
header('Content-Type: application/json; charset=utf-8');
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
?>关键改进说明:
立即学习“PHP免费学习笔记(深入)”;
-
结构隔离:每次循环创建全新
$storeData数组,确保各店铺数据互不干扰; -
顶层封装:使用
$response['DATA'][] = $storeData实现动态追加,自然形成"DATA"父数组; -
安全性强化:改用
mysqli::prepare()+bind_param()防止 SQL 注入(原代码中直接拼接$storeName存在严重风险); -
类型健壮性:对数值字段显式转为字符串
(string),避免 JSON 编码时出现null或科学计数法; -
错误防御:增加
fetch_assoc()判空逻辑,避免无数据时引发警告。
注意事项:
⚠️ 切勿在生产环境使用字符串拼接 SQL(如 "art_nazivProdavnice = '$storeName'"),极易导致 SQL 注入漏洞;
⚠️ 若 storeFullName() 返回值含特殊字符(如单引号),未预处理将直接破坏 SQL 语法;
⚠️ JSON_PRETTY_PRINT 仅建议开发调试时启用,上线后应移除以减小响应体积。
通过此方案,你将获得完全符合预期的嵌套 JSON 结构——每个店铺作为 "DATA" 数组中的独立对象,既清晰表达业务层级,又满足前后端协作的接口契约要求。



















