跳转到主内容
极星编程网:以代码为星,赴技术山海!

SQL存储过程如何实现父子结构路径展开_利用递归CTE拼接路径

MySQL 8.0+ 的 WITH RECURSIVE 可直接拼接完整路径,关键是在锚点中初始化 full_path 字段并逐层 CONCAT,方向应为 CONCAT(c.name, '/', p.full_path) 以确保顶级在左、符合导航习惯,同时需严格匹配 JOIN 条件、控制字段长度并避免分隔符冲突。 MySQL 8.0+ 用 WITH RECURSIVE 拼接完整路径最直接 只要 MySQL 版本 ≥ 8.0,
WITH RECURSIVE
是首选方案,不用写存储过程也能拼出带分隔符的完整路径。关键不是“能不能递归”,而是“怎么让路径字符串逐层累积”。 常见错误是只做层级遍历却不拼接字符串,结果查出来一堆 id 和 name,还得靠应用层再组装。 起始查询必须包含初始路径字段,类型要足够长(比如
CAST(name AS CHAR(1000))
),否则后续
CONCAT
会截断 递归部分的
JOIN
条件要严格匹配父级 ID,别写成
ON child.parent_id = parent.id
反了 路径分隔符建议用
/
或
→
,避免逗号、井号等可能出现在原始 name 中的字符 如果表有租户字段(如
tenant_id
),每一层递归都得带上该条件,否则跨租户污染数据 示例:从
categories
表查 id=4 的完整路径
WITH RECURSIVE path_cte AS ( SELECT id, name, parent_id, CAST(name AS CHAR(1000)) AS full_path FROM categories WHERE id = 4 UNION ALL SELECT c.id, c.name, c.parent_id, CONCAT(c.name, '/', p.full_path) FROM categories c INNER JOIN path_cte p ON c.id = p.parent_id WHERE c.parent_id IS NOT NULL ) SELECT full_path FROM path_cte WHERE parent_id IS NULL;
SQL Server 必须用函数 + 视图绕过 dbo 权限限制 SQL Server 自定义函数强制要求 schema 前缀(通常是
dbo.getChannelPath
),但 DM 数据库不认
dbo.
,硬套会报错
Invalid object name 'dbo.getChannelPath'
。这时候别硬改函数名,用视图桥接更稳妥。 函数本身保留
dbo.
前缀,确保 SQL Server 能调用 视图里调用该函数,对外暴露无 schema 的列名,比如
SELECT CHANNELID, dbo.getChannelPath(CHANNELID) AS channel_path FROM WCMCHANNEL
应用层统一查视图,DM 和 SQL Server 各自建同名视图(DM 用原生函数或子查询模拟路径逻辑) 注意函数中
WHILE
循环的退出条件必须明确,比如
@parent_Chnlid = 0
或
IS NULL
,否则容易死循环 MySQL 5.7 及以下只能靠存储过程或应用层拼接 没有
WITH RECURSIVE
就没法在单条 SQL 里完成路径展开,硬写存储过程反而增加维护成本。更实际的做法是:只查出父子关系链(用多次 JOIN 或应用层循环),再由代码拼字符串。 避免用
PROCEDURE get_tree_data
类递归调用——MySQL 存储过程不支持真正的递归调用,所谓“递归”其实是靠客户端反复请求模拟的 如果必须用存储过程,优先用游标 + 临时表缓存中间结果,而不是嵌套
CALL
路径长度不确定时,别用固定长度的
VARCHAR(255)
接收结果,容易截断;改用
TEXT
或加长度校验逻辑 测试时重点验证根节点(
parent_id IS NULL
)和叶子节点(无子记录)两种边界情况 路径拼接时 order by 容易被忽略的层级顺序问题 拼出来的路径是 “顶级→子级→孙级” 还是 “孙级→子级→顶级”,取决于
CONCAT
位置和递归方向。多数业务需要前者(便于前端按
/
切分导航),但 CTE 默认是自底向上查,所以得把新层级拼在左边。 正向路径(推荐):
CONCAT(c.name, '/', p.full_path)
—— 当前节点名在左,已拼路径在右 反向路径(慎用):
CONCAT(p.full_path, '/', c.name)
—— 导致路径变成 “当前→父→祖”,不符合常规导航习惯 如果要支持多根树(即多个
parent_id IS NULL
的起点),CTE 起始查询不能只写
WHERE id = ?
,得改成
WHERE parent_id IS NULL
并配合额外过滤条件 真正难的不是写对第一层递归,而是确保每层
full_path
字段的类型、长度、拼接方向都一致;一旦某一层 CAST 失败或 CONCAT 顺序错,整条路径就乱了。

相关文章