PHP或jQuery场景下如何封装MySQL查询的同用户多订单重复行数据
实现客户-订单嵌套结构的两种可行方案
方案一:数据库层直接聚合(推荐,MySQL 5.7+ 适用)
如果数据库版本支持原生JSON聚合函数,可以直接在SQL层面完成嵌套结构的生成,不需要PHP层做额外循环处理,整体执行效率最高,同时能减少重复字段的数据传输量。
对应的SQL实现:
SELECT JSON_OBJECT( 'usuario', JSON_OBJECT( 'nombre', c.nombre, 'telefono', c.telefono, 'calle', c.calle, 'no_ext', c.no_ext, 'colonia', c.colonia, 'cp', c.cp, 'ordenes', JSON_ARRAYAGG( JSON_OBJECT( 'id_orden', o.id_orden, 'articulos', o.articulos, 'total', o.total, 'estado', o.estado ) ) ) ) AS resultado FROM CLIENTES c INNER JOIN ORDENES o ON c.telefono = o.id_cliente GROUP BY c.telefono, c.nombre, c.calle, c.no_ext, c.colonia, c.cp ORDER BY c.telefono, o.id_orden ASC;
PHP层只需要简单遍历结果集,把每行生成的JSON对象收集为数组即可:
$result = mysqli_query($connection, $sql) or die("Error en la ejecución de la consulta " . mysqli_error($connection)); $emparray = []; while($row = mysqli_fetch_assoc($result)){ // 直接解码数据库生成的JSON对象,加入最终数组 $emparray[] = json_decode($row['resultado'], true); } echo json_encode($emparray);
注意:因为SQL用了
INNER JOIN,没有关联订单的客户会被过滤,和你当前的查询逻辑保持一致;如果需要保留无订单的客户,只要把INNER JOIN改成LEFT JOIN,JSON_ARRAYAGG会自动对无订单的情况返回空数组,不需要额外处理。
方案二:PHP层结果聚合(兼容所有MySQL版本)
如果数据库版本低于5.7,没有JSON函数支持,可以在现有查询的基础上,通过遍历结果集的方式聚合数据。因为你当前的SQL已经按客户标识、订单ID做了排序,整个遍历过程只需要执行一次,不会产生性能问题。
修改后的PHP代码实现:
$sql = "SELECT c.nombre, c.telefono, c.calle, c.no_ext, c.colonia, c.cp, o.id_orden, o.articulos, o.total, o.estado, o.reg_fecha FROM CLIENTES c INNER JOIN ORDENES o ON c.telefono = o.id_cliente ORDER BY o.id_cliente, o.id_orden ASC"; $result = mysqli_query($connection, $sql) or die("Error en la ejecución de la consulta " . mysqli_error($connection)); $emparray = []; $clientIndexMap = []; // 缓存每个客户在最终数组中的位置,避免重复查找 while($row = mysqli_fetch_assoc($result)){ // 用客户唯一标识(当前表结构里用telefono做关联键)判断是否为首次遍历到该客户 $clientUniqueKey = $row['telefono']; if(!isset($clientIndexMap[$clientUniqueKey])){ // 首次遇到客户,初始化完整的嵌套结构 $userNode = [ 'usuario' => [ 'nombre' => $row['nombre'], 'telefono' => $row['telefono'], 'calle' => $row['calle'], 'no_ext' => $row['no_ext'], 'colonia' => $row['colonia'], 'cp' => $row['cp'], 'ordenes' => [] ] ]; // 把当前行的订单信息加入数组 $userNode['usuario']['ordenes'][] = [ 'id_orden' => $row['id_orden'], 'articulos' => $row['articulos'], 'total' => $row['total'], 'estado' => $row['estado'] ]; // 存入最终数组,记录索引位置 $emparray[] = $userNode; $clientIndexMap[$clientUniqueKey] = count($emparray) - 1; } else { // 非首次遇到客户,直接把新的订单信息追加到对应客户的订单列表里 $targetIndex = $clientIndexMap[$clientUniqueKey]; $emparray[$targetIndex]['usuario']['ordenes'][] = [ 'id_orden' => $row['id_orden'], 'articulos' => $row['articulos'], 'total' => $row['total'], 'estado' => $row['estado'] ]; } } echo json_encode($emparray);
结构修正提示
你之前写的期望结构存在JSON语法错误,直接使用会导致前端解析失败,正确的结构应该符合JSON语法规范:
- 数组不能直接包含无键的键值对,外层如果是列表形式,每个元素必须是合法的对象
- 订单列表是多个元素的集合,必须用方括号
[]包裹成数组,不能用对象的大括号{} - 修正后的正确结构参考:
[ { "usuario": { "nombre": "Jane Doe", "telefono": "5512345678", "calle": "Far far away", "no_ext": "113", "colonia": "Cumbres", "cp": "12345", "ordenes": [ { "id_orden": "1", "articulos": "2", "total": "120", "estado": "1" }, { "id_orden": "2", "articulos": "1", "total": "90", "estado": "3" } ] } } ]
内容的提问来源于stack exchange,提问作者IRH
相关产品推荐
相关产品推荐

