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

无预定义父子ID时 MySQL5.7+PHP构建层级数组实现方案

问题背景
  • 运行环境为MySQL 5.7,版本不支持Common Table Expressions(公共表表达式),无法直接通过SQL递归查询构建「区域-办公室-员工」三级层级关系
  • 此前尝试在SQL层通过动态生成ID、ParentID的方式拼接层级,需要编写大量子查询,实现和维护成本很高
  • 目标方案:直接获取SQL返回的平面结果集,通过PHP代码处理生成带Item、Children节点的多层嵌套层级数组
输入输出示例

输入:数据库返回平面数组

数据库查询返回的$dbResponse为二维平面结构,每行包含Region、Office、Employee三个字段,示例如下:

$dbResponse = [
    ['Region' => '华东区', 'Office' => '上海办公室', 'Employee' => '张三'],
    ['Region' => '华东区', 'Office' => '上海办公室', 'Employee' => '李四'],
    ['Region' => '华东区', 'Office' => '杭州办公室', 'Employee' => '王五'],
    ['Region' => '华南区', 'Office' => '广州办公室', 'Employee' => '赵六'],
    ['Region' => '华南区', 'Office' => '深圳办公室', 'Employee' => '孙七'],
];

期望输出:嵌套层级数组

输出结构每层统一包含Item(存储当前节点信息)、Children(存储子节点数组)两个字段,三级嵌套示例如下:

$newOutput = [
    [
        'Item' => ['Name' => '华东区', 'Type' => 'Region'],
        'Children' => [
            [
                'Item' => ['Name' => '上海办公室', 'Type' => 'Office'],
                'Children' => [
                    ['Item' => ['Name' => '张三', 'Type' => 'Employee'], 'Children' => []],
                    ['Item' => ['Name' => '李四', 'Type' => 'Employee'], 'Children' => []]
                ]
            ],
            [
                'Item' => ['Name' => '杭州办公室', 'Type' => 'Office'],
                'Children' => [
                    ['Item' => ['Name' => '王五', 'Type' => 'Employee'], 'Children' => []]
                ]
            ]
        ]
    ],
    [
        'Item' => ['Name' => '华南区', 'Type' => 'Region'],
        'Children' => [
            [
                'Item' => ['Name' => '广州办公室', 'Type' => 'Office'],
                'Children' => [
                    ['Item' => ['Name' => '赵六', 'Type' => 'Employee'], 'Children' => []]
                ]
            ],
            [
                'Item' => ['Name' => '深圳办公室', 'Type' => 'Office'],
                'Children' => [
                    ['Item' => ['Name' => '孙七', 'Type' => 'Employee'], 'Children' => []]
                ]
            ]
        ]
    ]
];
PHP实现方案

核心思路

不需要写递归,通过两层映射表存储已创建节点的引用,单次遍历平面结果集即可完成层级构建,时间复杂度O(n),性能远高于递归查找方案:

  • 遍历每行数据时,按「区域→办公室→员工」的顺序逐层判断节点是否已创建
  • 未创建的节点初始化后推入对应父节点的Children数组,同时在映射表中存储该节点的引用
  • 已存在的节点直接通过映射表拿到引用,追加下一级节点即可

可直接运行的实现代码

function buildRegionHierarchy(array $dbResponse): array
{
    $hierarchy = [];
    // 映射表存储已创建节点的引用,避免重复遍历查找
    $regionMap = [];
    $officeMap = [];

    foreach ($dbResponse as $row) {
        $regionName = $row['Region'];
        $officeName = $row['Office'];
        $employeeName = $row['Employee'];

        // 处理区域层级节点
        if (!isset($regionMap[$regionName])) {
            $regionNode = [
                'Item' => ['Name' => $regionName, 'Type' => 'Region'],
                'Children' => []
            ];
            $hierarchy[] = &$regionNode;
            $regionMap[$regionName] = &$regionNode;
            $officeMap[$regionName] = [];
            unset($regionNode);
        }

        // 处理办公室层级节点
        if (!isset($officeMap[$regionName][$officeName])) {
            $officeNode = [
                'Item' => ['Name' => $officeName, 'Type' => 'Office'],
                'Children' => []
            ];
            $regionMap[$regionName]['Children'][] = &$officeNode;
            $officeMap[$regionName][$officeName] = &$officeNode;
            unset($officeNode);
        }

        // 处理员工层级节点
        $officeMap[$regionName][$officeName]['Children'][] = [
            'Item' => ['Name' => $employeeName, 'Type' => 'Employee'],
            'Children' => []
        ];
    }

    // 释放引用,避免后续变量操作污染数组结构
    unset($regionMap, $officeMap);
    return $hierarchy;
}

// 调用示例
$newOutput = buildRegionHierarchy($dbResponse);

注意:代码中使用引用是为了简化多层数组的操作,遍历完成后必须手动unset引用变量,否则可能出现非预期的数组值污染。如果后续需要扩展层级(比如新增员工下属层级),只需要对应增加一层映射判断逻辑即可,不需要重构整体实现。

内容的提问来源于stack exchange,提问作者Rob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.16 16:15:41