You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 12:45:02